From 56febbf2bac2c51d9478616a1dd28243ef03f406 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 4 Aug 2016 10:39:28 -0700 Subject: . --- node/Peer.cpp | 99 +++++------------------------------------------------------ 1 file changed, 7 insertions(+), 92 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index cc581004..a994c4b2 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -371,80 +371,6 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) } } -bool Peer::networkMembershipCertificatesAgree(uint64_t nwid,const CertificateOfMembership &com) const -{ - Mutex::Lock _l(_networkComs_m); - const _NetworkCom *ourCom = _networkComs.get(nwid); - if (ourCom) - return ourCom->com.agreesWith(com); - return false; -} - -bool Peer::validateAndSetNetworkMembershipCertificate(uint64_t nwid,const CertificateOfMembership &com) -{ - // Sanity checks - if ((!com)||(com.issuedTo() != _id.address())) - return false; - - // Return true if we already have this *exact* COM - { - Mutex::Lock _l(_networkComs_m); - _NetworkCom *ourCom = _networkComs.get(nwid); - if ((ourCom)&&(ourCom->com == com)) - return true; - } - - // Check signature, log and return if cert is invalid - if (com.signedBy() != Network::controllerFor(nwid)) { - TRACE("rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network",(unsigned long long)nwid,com.signedBy().toString().c_str()); - return false; // invalid signer - } - - if (com.signedBy() == RR->identity.address()) { - - // We are the controller: RR->identity.address() == controller() == cert.signedBy() - // So, verify that we signed th cert ourself - if (!com.verify(RR->identity)) { - TRACE("rejected network membership certificate for %.16llx self signed by %s: signature check failed",(unsigned long long)nwid,com.signedBy().toString().c_str()); - return false; // invalid signature - } - - } else { - - SharedPtr signer(RR->topology->getPeer(com.signedBy())); - - if (!signer) { - // This would be rather odd, since this is our controller... could happen - // if we get packets before we've gotten config. - RR->sw->requestWhois(com.signedBy()); - return false; // signer unknown - } - - if (!com.verify(signer->identity())) { - TRACE("rejected network membership certificate for %.16llx signed by %s: signature check failed",(unsigned long long)nwid,com.signedBy().toString().c_str()); - return false; // invalid signature - } - } - - // If we made it past all those checks, add or update cert in our cert info store - { - Mutex::Lock _l(_networkComs_m); - _networkComs.set(nwid,_NetworkCom(RR->node->now(),com)); - } - - return true; -} - -bool Peer::needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime) -{ - Mutex::Lock _l(_networkComs_m); - uint64_t &lastPushed = _lastPushedComs[nwid]; - const uint64_t tmp = lastPushed; - if (updateLastPushedTime) - lastPushed = now; - return ((now - tmp) >= (ZT_NETWORK_AUTOCONF_DELAY / 3)); -} - void Peer::clean(uint64_t now) { { @@ -460,24 +386,13 @@ void Peer::clean(uint64_t now) } { - Mutex::Lock _l(_networkComs_m); - { - uint64_t *k = (uint64_t *)0; - _NetworkCom *v = (_NetworkCom *)0; - Hashtable< uint64_t,_NetworkCom >::Iterator i(_networkComs); - while (i.next(k,v)) { - if ( (!RR->node->belongsToNetwork(*k)) && ((now - v->ts) >= ZT_PEER_NETWORK_COM_EXPIRATION) ) - _networkComs.erase(*k); - } - } - { - uint64_t *k = (uint64_t *)0; - uint64_t *v = (uint64_t *)0; - Hashtable< uint64_t,uint64_t >::Iterator i(_lastPushedComs); - while (i.next(k,v)) { - if ((now - *v) > (ZT_NETWORK_AUTOCONF_DELAY * 2)) - _lastPushedComs.erase(*k); - } + Mutex::Lock _l(_memberships_m); + uint64_t *nwid = (uint64_t *)0; + Membership *m = (Membership *)0; + Hashtable::Iterator i(_memberships); + while (i.next(nwid,m)) { + if ((now - m->clean(now)) > ZT_MEMBERSHIP_EXPIRATION_TIME) + _memberships.erase(*nwid); } } } -- cgit v1.2.3 From e2f783ebbd39466bc03bf115b20064d222b91944 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 5 Aug 2016 15:02:01 -0700 Subject: . --- attic/LockingPtr.hpp | 99 +++++++++++ include/ZeroTierOne.h | 85 ++++++++-- node/Capability.hpp | 33 ++-- node/Hashtable.hpp | 4 +- node/LockingPtr.hpp | 99 ----------- node/Membership.cpp | 43 +++-- node/Membership.hpp | 56 ++++--- node/Network.cpp | 400 ++++++++++++++++++++++++++++++++++++++++++++- node/Network.hpp | 7 +- node/OutboundMulticast.cpp | 11 +- node/Packet.hpp | 2 + node/Peer.cpp | 29 +--- node/Peer.hpp | 33 ---- node/Tag.hpp | 2 +- 14 files changed, 660 insertions(+), 243 deletions(-) create mode 100644 attic/LockingPtr.hpp delete mode 100644 node/LockingPtr.hpp (limited to 'node/Peer.cpp') diff --git a/attic/LockingPtr.hpp b/attic/LockingPtr.hpp new file mode 100644 index 00000000..c373129a --- /dev/null +++ b/attic/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 . + */ + +#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 +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(&p)->_lock = (Mutex *)0; + } + + ~LockingPtr() + { + if (_lock) + _lock->unlock(); + } + + inline LockingPtr &operator=(const LockingPtr &p) + { + _ptr = p._ptr; + _lock = p._lock; + const_cast(&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/include/ZeroTierOne.h b/include/ZeroTierOne.h index 2a70417e..aa7ecc2c 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -165,9 +165,69 @@ extern "C" { #define ZT_CLUSTER_MAX_MESSAGE_LENGTH (1500 - 48) /** - * Packet characteristics flag: packet direction, 1 for incoming 0 for outgoing + * Packet characteristics flag: packet direction, 1 if inbound 0 if outbound */ -#define ZT_RULE_PACKET_CHARACTERISTICS_0_INBOUND 0x0000000000000001ULL +#define ZT_RULE_PACKET_CHARACTERISTICS_INBOUND 0x8000000000000000ULL + +/** + * Packet characteristics flag: TCP left-most reserved bit + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_0 0x0000000000000800ULL + +/** + * Packet characteristics flag: TCP middle reserved bit + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_1 0x0000000000000400ULL + +/** + * Packet characteristics flag: TCP right-most reserved bit + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_2 0x0000000000000200ULL + +/** + * Packet characteristics flag: TCP NS flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_NS 0x0000000000000100ULL + +/** + * Packet characteristics flag: TCP CWR flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_CWR 0x0000000000000080ULL + +/** + * Packet characteristics flag: TCP ECE flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ECE 0x0000000000000040ULL + +/** + * Packet characteristics flag: TCP URG flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_URG 0x0000000000000020ULL + +/** + * Packet characteristics flag: TCP ACK flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK 0x0000000000000010ULL + +/** + * Packet characteristics flag: TCP PSH flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_PSH 0x0000000000000008ULL + +/** + * Packet characteristics flag: TCP RST flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RST 0x0000000000000004ULL + +/** + * Packet characteristics flag: TCP SYN flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN 0x0000000000000002ULL + +/** + * Packet characteristics flag: TCP FIN flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL /** * A null/empty sockaddr (all zero) to signify an unspecified socket address @@ -533,19 +593,24 @@ enum ZT_VirtualNetworkRuleType ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 49, /** - * Match a range of tag values (equality match if start==end) + * Match if local and remote tags differ by no more than value, use 0 to check for equality + */ + ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS = 50, + + /** + * Match if local and remote tags ANDed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE = 50, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 51, /** - * Match if all bits are set in a tag value + * Match if local and remote tags ANDed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL = 51, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 52, /** - * Match if any bit from a mask is set in a tag value + * Match if local and remote tags XORed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY = 52 + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 53 }; /** @@ -650,11 +715,11 @@ typedef struct uint16_t frameSize[2]; /** - * For matching tag values + * For tag-related rules */ struct { uint32_t id; - uint32_t value[2]; // only [0] is used for BITS_ALL or BITS_ANY, [0]-[1] for range + uint32_t value; } tag; } v; } ZT_VirtualNetworkRule; diff --git a/node/Capability.hpp b/node/Capability.hpp index d9b49121..53457d4d 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -52,13 +52,13 @@ class RuntimeEnvironment; * On the receiving side the receiver does the following for each packet: * * (1) Evaluates the capabilities of the sender (that the sender has - * presented) to determine if the sender was allowed to send this. + * presented) to determine if it should received this packet. * (2) Evaluates its own capabilities to determine if it should receive - * and process this packet. + * this packet. * (3) If both check out, it receives the packet. * * Note that rules in capabilities can do other things as well such as TEE - * or REDIRECT packets. See Filter and ZT_VirtualNetworkRule. + * or REDIRECT packets. See filter code and ZT_VirtualNetworkRule. */ class Capability { @@ -248,17 +248,13 @@ public: b.append((uint16_t)rules[i].v.frameSize[0]); b.append((uint16_t)rules[i].v.frameSize[1]); break; - case ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE: - b.append((uint8_t)12); - b.append((uint32_t)rules[i].v.tag.id); - b.append((uint32_t)rules[i].v.tag.value[0]); - b.append((uint32_t)rules[i].v.tag.value[1]); - break; - case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL: - case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY: + case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: b.append((uint8_t)8); b.append((uint32_t)rules[i].v.tag.id); - b.append((uint32_t)rules[i].v.tag.value[0]); + b.append((uint32_t)rules[i].v.tag.value); break; } } @@ -360,15 +356,12 @@ public: rules[i].v.frameSize[0] = b.template at(p); rules[i].v.frameSize[0] = b.template at(p + 2); break; - case ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE: - rules[i].v.tag.id = b.template at(p); - rules[i].v.tag.value[0] = b.template at(p + 4); - rules[i].v.tag.value[1] = b.template at(p + 8); - break; - case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL: - case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY: + case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: rules[i].v.tag.id = b.template at(p); - rules[i].v.tag.value[0] = b.template at(p + 4); + rules[i].v.tag.value = b.template at(p + 4); break; } p += fieldLen; diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index f06b2230..c550191e 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -103,9 +103,9 @@ public: friend class Hashtable::Iterator; /** - * @param bc Initial capacity in buckets (default: 128, must be nonzero) + * @param bc Initial capacity in buckets (default: 64, must be nonzero) */ - Hashtable(unsigned long bc = 128) : + Hashtable(unsigned long bc = 64) : _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))), _bc(bc), _s(0) diff --git a/node/LockingPtr.hpp b/node/LockingPtr.hpp deleted file mode 100644 index c373129a..00000000 --- a/node/LockingPtr.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 . - */ - -#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 -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(&p)->_lock = (Mutex *)0; - } - - ~LockingPtr() - { - if (_lock) - _lock->unlock(); - } - - inline LockingPtr &operator=(const LockingPtr &p) - { - _ptr = p._ptr; - _lock = p._lock; - const_cast(&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.cpp b/node/Membership.cpp index a1a8eb8a..37b2c16d 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -28,49 +28,44 @@ namespace ZeroTier { -bool Membership::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) +bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const CertificateOfMembership &com,const Capability *cap,const Tag **tags,const unsigned int tagCount) { try { Buffer capsAndTags; - capsAndTags.addSize(2); unsigned int appendedCaps = 0; - for(unsigned int i=0;iid()); if ((now - cs->lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) { - if ((capsAndTags.size() + sizeof(Capability)) > (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) - break; - const Capability *c = nconf.capability(capIds[i]); - if (c) { - c->serialize(capsAndTags); - ++appendedCaps; - cs->lastPushed = now; - } + cap->serialize(capsAndTags); + cs->lastPushed = now; + ++appendedCaps; } + capsAndTags.setAt(0,(uint16_t)appendedCaps); + } else { + capsAndTags.append((uint16_t)0); } - capsAndTags.setAt(0,(uint16_t)appendedCaps); + unsigned int appendedTags = 0; const unsigned int tagCountPos = capsAndTags.size(); capsAndTags.addSize(2); - unsigned int appendedTags = 0; for(unsigned int i=0;iid()); if ((now - ts->lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) { if ((capsAndTags.size() + sizeof(Tag)) > (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) break; - const Tag *t = nconf.tag(tagIds[i]); - if (t) { - t->serialize(capsAndTags); - ++appendedTags; - ts->lastPushed = now; - } + tags[i]->serialize(capsAndTags); + ts->lastPushed = now; + ++appendedTags; } } capsAndTags.setAt(tagCountPos,(uint16_t)appendedTags); - if (((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)||(appendedCaps)||(appendedTags)) { - Packet outp(peer.address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - nconf.com.serialize(outp); + if ( ((com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)) || (appendedCaps) || (appendedTags) ) { + Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + if (com) + com.serialize(outp); outp.append((uint8_t)0x00); outp.append(capsAndTags.data(),capsAndTags.size()); outp.compress(); diff --git a/node/Membership.hpp b/node/Membership.hpp index 0e72b7b1..3db25488 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -40,7 +40,6 @@ namespace ZeroTier { -class Peer; class RuntimeEnvironment; /** @@ -54,18 +53,18 @@ private: struct TState { TState() : lastPushed(0),lastReceived(0) {} - // Last time we pushed this tag to this peer + // Last time we pushed our tag to this peer (our tag with the same ID) uint64_t lastPushed; // Last time we received this tag from this peer uint64_t lastReceived; - // Tag from peer + // Tag from peer (remote tag) Tag tag; }; struct CState { CState() : lastPushed(0),lastReceived(0) {} - // Last time we pushed this capability to this peer + // Last time we pushed our capability to this peer (our capability with this ID) uint64_t lastPushed; // Last time we received this capability from this peer uint64_t lastReceived; @@ -90,29 +89,14 @@ public: * * @param RR Runtime environment * @param now Current time - * @param peer Peer that "owns" this membership - * @param nconf Network configuration - * @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 peerAddress Address of member peer + * @param com Network certificate of membership (if any) + * @param cap Capability to send or 0 if none + * @param tags Tags that this peer might need * @param tagCount Number of tag IDs * @return True if we pushed something */ - 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); - - /** - * Send COM if needed - * - * @param RR Runtime environment - * @param now Current time - * @param peer Peer that "owns" this membership - * @param nconf Network configuration - * @return True if we pushed something - */ - inline bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf) - { - return sendCredentialsIfNeeded(RR,now,peer,nconf,(const uint32_t *)0,0,(const uint32_t *)0,0); - } + bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const CertificateOfMembership &com,const Capability *cap,const Tag **tags,const unsigned int tagCount); /** * @return This peer's COM if they have sent one @@ -130,6 +114,30 @@ public: return ((t) ? (((t->lastReceived != 0)&&(t->tag.expiration() < nconf.timestamp)) ? &(t->tag) : (const Tag *)0) : (const Tag *)0); } + /** + * @param nconf Network configuration + * @param ids Array to store IDs into + * @param values Array to store values into + * @param maxTags Capacity of ids[] and values[] + * @return Number of tags added to arrays + */ + inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const + { + unsigned int n = 0; + uint32_t *id = (uint32_t *)0; + TState *ts = (TState *)0; + Hashtable::Iterator i(const_cast(this)->_tags); + while (i.next(id,ts)) { + if ((ts->lastReceived)&&(ts->tag.expiration() < nconf.timestamp)) { + if (n >= maxTags) + return n; + ids[n] = *id; + values[n] = ts->tag.value(); + } + } + return n; + } + /** * @param nconf Network configuration * @param id Capablity ID diff --git a/node/Network.cpp b/node/Network.cpp index 485a598b..314edf5c 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -22,19 +22,313 @@ #include #include "Constants.hpp" +#include "../version.h" #include "Network.hpp" #include "RuntimeEnvironment.hpp" +#include "MAC.hpp" +#include "Address.hpp" +#include "InetAddress.hpp" #include "Switch.hpp" -#include "Packet.hpp" #include "Buffer.hpp" +#include "Packet.hpp" #include "NetworkController.hpp" #include "Node.hpp" #include "Peer.hpp" -#include "../version.h" - namespace ZeroTier { +// 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) +{ + if (frameLen < 40) + return false; + pos = 40; + proto = frameData[6]; + while (pos <= frameLen) { + switch(proto) { + case 0: // hop-by-hop options + case 43: // routing + case 60: // destination options + case 135: // mobility options + if ((pos + 8) > frameLen) + return false; // invalid! + proto = frameData[pos]; + pos += ((unsigned int)frameData[pos + 1] * 8) + 8; + break; + + //case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway + //case 50: + //case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff + default: + return true; + } + } + return false; // overflow == invalid +} + +static bool _doZtFilter( + const RuntimeEnvironment *RR, + const uint64_t nwid, + const bool inbound, + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const ZT_VirtualNetworkRule *rules, + const unsigned int ruleCount, + const Tag *localTags, + const unsigned int localTagCount, + const uint32_t *remoteTagIds, + const uint32_t *remoteTagValues, + const unsigned int remoteTagCount, + const Tag **relevantLocalTags, // pointer array must be at least [localTagCount] in size + unsigned int &relevantLocalTagCount) +{ + // For each set of rules we start by assuming that they match (since no constraints + // yields a 'match all' rule). + uint8_t thisSetMatches = 1; + + for(unsigned int rn=0;rnidentity.address(),Packet::VERB_EXT_FRAME); + outp.append(nwid); + outp.append((uint8_t)((rt == ZT_NETWORK_RULE_ACTION_REDIRECT) ? 0x04 : 0x02)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData,frameLen); + outp.compress(); + RR->sw->send(outp,true,nwid); + + if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { + return false; + } else { + thisSetMatches = 1; // TEE does not terminate parsing + } + } break; + + // Rules --------------------------------------------------------------- + + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); + break; + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + // NOT SUPPORTED YET + thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + // NOT SUPPORTED YET + thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macSource); + break; + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macDest); + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0))); + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0))); + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { + thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0))); + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { + thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0))); + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((frameData[1] & 0xfc) >> 2)); + } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { + const uint8_t trafficClass = ((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f); + thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((trafficClass & 0xfc) >> 2)); + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); + } else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0,proto = 0; + if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); + } else { + thisRuleMatches = 0; + } + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + const unsigned int headerLen = 4 * (frameData[0] & 0xf); + int p = -1; + switch(frameData[9]) { // IP protocol number + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (headerLen + 4)) { + unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); + p = (int)frameData[pos++] << 8; + p |= (int)frameData[pos]; + } + break; + } + thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; + } else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0,proto = 0; + if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { + int p = -1; + switch(proto) { // IP protocol number + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (pos + 4)) { + if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2; + p = (int)frameData[pos++] << 8; + p |= (int)frameData[pos]; + } + break; + } + thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; + } else { + thisRuleMatches = 0; + } + } else { + thisRuleMatches = 0; + } + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { + uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)&&(frameData[9] == 0x06)) { + const unsigned int headerLen = 4 * (frameData[0] & 0xf); + cf |= (uint64_t)frameData[headerLen + 13]; + cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0f)) << 8); + } else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0,proto = 0; + if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { + if ((proto == 0x06)&&(frameLen > (pos + 14))) { + cf |= (uint64_t)frameData[pos + 13]; + cf |= (((uint64_t)(frameData[pos + 12] & 0x0f)) << 8); + } + } + } + thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics[0]) == rules[rn].v.characteristics[1]); + } break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + 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_TAGS_SAMENESS: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: { + const Tag *lt = (const Tag *)0; + for(unsigned int i=0;ivalue() > *rtv) ? (lt->value() - *rtv) : (*rtv - lt->value()); + thisRuleMatches = (uint8_t)(sameness <= rules[rn].v.tag.value); + } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { + thisRuleMatches = (uint8_t)((lt->value() & *rtv) <= rules[rn].v.tag.value); + } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { + thisRuleMatches = (uint8_t)((lt->value() | *rtv) <= rules[rn].v.tag.value); + } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { + thisRuleMatches = (uint8_t)((lt->value() ^ *rtv) <= rules[rn].v.tag.value); + } else { // sanity check, can't really happen + thisRuleMatches = 0; + } + if (thisRuleMatches) { + relevantLocalTags[relevantLocalTagCount++] = lt; + } + } + } + } break; + } + + // thisSetMatches remains true if the current rule matched... or does NOT match if not bit (0x80) is 1 + thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t & 0x80) >> 7)); + + //TRACE("[%u] %u result==%u set==%u",rn,(unsigned int)rt,(unsigned int)thisRuleMatches,(unsigned int)thisSetMatches); + } + + return false; +} + const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : @@ -100,6 +394,96 @@ Network::~Network() } } +bool Network::filterOutgoingPacket( + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId) +{ + uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; + uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; + const Tag *relevantLocalTags[ZT_MAX_NETWORK_TAGS]; + unsigned int relevantLocalTagCount = 0; + + Mutex::Lock _l(_lock); + + Membership &m = _memberships[ztDest]; + const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); + + if (_doZtFilter( + RR, + _id, + false, + ztSource, + ztDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + _config.rules, + _config.ruleCount, + _config.tags, + _config.tagCount, + remoteTagIds, + remoteTagValues, + remoteTagCount, + relevantLocalTags, + relevantLocalTagCount + )) { + m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config.com,(const Capability *)0,relevantLocalTags,relevantLocalTagCount); + return true; + } + + for(unsigned int c=0;c<_config.capabilityCount;++c) { + relevantLocalTagCount = 0; + if (_doZtFilter( + RR, + _id, + false, + ztSource, + ztDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + _config.capabilities[c].rules(), + _config.capabilities[c].ruleCount(), + _config.tags, + _config.tagCount, + remoteTagIds, + remoteTagValues, + remoteTagCount, + relevantLocalTags, + relevantLocalTagCount + )) { + m.sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config.com,&(_config.capabilities[c]),relevantLocalTags,relevantLocalTagCount); + return true; + } + } + + return false; +} + +bool Network::filterIncomingPacket( + const SharedPtr &sourcePeer, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId) +{ +} + bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const { Mutex::Lock _l(_lock); @@ -267,6 +651,16 @@ void Network::clean() _multicastGroupsBehindMe.erase(*mg); } } + + { + Address *a = (Address *)0; + Membership *m = (Membership *)0; + Hashtable::Iterator i(_memberships); + while (i.next(a,m)) { + if ((now - m->clean(now)) > ZT_MEMBERSHIP_EXPIRATION_TIME) + _memberships.erase(*a); + } + } } void Network::learnBridgeRoute(const MAC &mac,const Address &addr) diff --git a/node/Network.hpp b/node/Network.hpp index 10714a7a..a8eb3156 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -40,6 +40,7 @@ #include "MAC.hpp" #include "Dictionary.hpp" #include "Multicaster.hpp" +#include "Membership.hpp" #include "NetworkConfig.hpp" #include "CertificateOfMembership.hpp" @@ -113,7 +114,7 @@ public: * a match certain actions may be taken such as sending a copy of the packet * to a TEE or REDIRECT target. * - * @param ztSource Source Peer (to save an extra lookup) + * @param sourcePeer Source Peer * @param ztDest Destination ZeroTier address * @param macSource Ethernet layer source address * @param macDest Ethernet layer destination address @@ -124,7 +125,7 @@ public: * @return True if packet should be accepted locally */ bool filterIncomingPacket( - const SharedPtr &ztSource, + const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, const MAC &macDest, @@ -387,6 +388,8 @@ private: } _netconfFailure; volatile int _portError; // return value from port config callback + Hashtable _memberships; + Mutex _lock; AtomicCounter __refCount; diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 11268fe2..a5856164 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -39,19 +39,22 @@ void OutboundMulticast::init( const void *payload, unsigned int len) { + uint8_t flags = 0; + _timestamp = timestamp; _nwid = nwid; - if (src) + if (src) { _macSrc = src; - else _macSrc.fromAddress(RR->identity.address(),nwid); + flags |= 0x04; + } else { + _macSrc.fromAddress(RR->identity.address(),nwid); + } _macDest = dest.mac(); _limit = limit; _frameLen = (len < ZT_MAX_MTU) ? len : ZT_MAX_MTU; _etherType = etherType; - uint8_t flags = 0; if (gatherLimit) flags |= 0x02; - if (src) flags |= 0x04; /* TRACE(">>MC %.16llx INIT %.16llx/%s limit %u gatherLimit %u from %s to %s length %u", diff --git a/node/Packet.hpp b/node/Packet.hpp index 977dc1bc..6789580e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -660,6 +660,8 @@ public: * * Flags: * 0x01 - Certificate of network membership attached (DEPRECATED) + * 0x02 - Packet is a TEE'd packet + * 0x04 - Packet is a REDIRECT'ed packet * * An extended frame carries full MAC addressing, making them a * superset of VERB_FRAME. They're used for bridging or when we diff --git a/node/Peer.cpp b/node/Peer.cpp index a994c4b2..ba47a0be 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -373,28 +373,15 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) void Peer::clean(uint64_t now) { - { - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if (_paths[x].active(now)) - _paths[y++] = _paths[x]; - ++x; - } - _numPaths = y; - } - - { - Mutex::Lock _l(_memberships_m); - uint64_t *nwid = (uint64_t *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(nwid,m)) { - if ((now - m->clean(now)) > ZT_MEMBERSHIP_EXPIRATION_TIME) - _memberships.erase(*nwid); - } + unsigned int np = _numPaths; + unsigned int x = 0; + unsigned int y = 0; + while (x < np) { + if (_paths[x].active(now)) + _paths[y++] = _paths[x]; + ++x; } + _numPaths = y; } void Peer::_doDeadPathDetection(Path &p,const uint64_t now) diff --git a/node/Peer.hpp b/node/Peer.hpp index 8b50f429..d8c44ebe 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -40,10 +40,8 @@ #include "SharedPtr.hpp" #include "AtomicCounter.hpp" #include "Hashtable.hpp" -#include "Membership.hpp" #include "Mutex.hpp" #include "NonCopyable.hpp" -#include "LockingPtr.hpp" namespace ZeroTier { @@ -386,34 +384,6 @@ 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(const uint64_t networkId,bool createIfMissing) - { - _memberships_m.lock(); - try { - if (createIfMissing) { - return LockingPtr(&(_memberships[networkId]),&_memberships_m); - } else { - Membership *m = _memberships.get(networkId); - if (m) { - return LockingPtr(m,&_memberships_m); - } else { - _memberships_m.unlock(); - return LockingPtr(); - } - } - } catch ( ... ) { - _memberships_m.unlock(); - throw; - } - } - /** * Find a common set of addresses by which two peers can link, if any * @@ -460,9 +430,6 @@ private: unsigned int _latency; unsigned int _directPathPushCutoffCount; - Hashtable _memberships; - Mutex _memberships_m; - AtomicCounter __refCount; }; diff --git a/node/Tag.hpp b/node/Tag.hpp index dcf2eb20..a9f6f57e 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -79,7 +79,7 @@ public: inline uint64_t networkId() const { return _nwid; } inline uint64_t expiration() const { return _expiration; } inline uint32_t id() const { return _id; } - inline uint32_t value() const { return _value; } + inline const uint32_t &value() const { return _value; } inline const Address &issuedTo() const { return _issuedTo; } inline const Address &signedBy() const { return _signedBy; } -- cgit v1.2.3 From 00fd9c3a15f9ac0981cf79c98515df888b3bd109 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 Aug 2016 17:33:26 -0700 Subject: It builds... almost ready to test some rules engine stuff. --- node/Capability.hpp | 35 ++++++++++++++++++------------- node/IncomingPacket.cpp | 55 +++++++++++++++++++++++++------------------------ node/Membership.cpp | 22 +++++++++++--------- node/Membership.hpp | 6 +++--- node/Multicaster.cpp | 15 +------------- node/Multicaster.hpp | 2 -- node/Network.cpp | 2 +- node/Network.hpp | 36 ++++++++++++++++++++++++++++++++ node/Packet.cpp | 5 ++--- node/Packet.hpp | 4 ++-- node/Peer.cpp | 4 +--- node/Switch.cpp | 53 +++++++---------------------------------------- node/Tag.hpp | 8 ++++++- node/Topology.cpp | 28 ------------------------- 14 files changed, 121 insertions(+), 154 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Capability.hpp b/node/Capability.hpp index 53457d4d..42d4ce63 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -71,16 +71,18 @@ public: /** * @param id Capability ID * @param nwid Network ID + * @param ts Timestamp (at controller) * @param expiration Expiration relative to network config timestamp * @param name Capability short name (max strlen == ZT_MAX_CAPABILITY_NAME_LENGTH, overflow ignored) * @param mccl Maximum custody chain length (1 to create non-transferrable capability) * @param rules Network flow rules for this capability * @param ruleCount Number of flow rules */ - Capability(uint32_t id,uint64_t nwid,uint64_t expiration,const char *name,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) + Capability(uint32_t id,uint64_t nwid,uint64_t ts,uint64_t expiration,const char *name,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) { memset(this,0,sizeof(Capability)); _nwid = nwid; + _ts = ts; _expiration = expiration; _id = id; _maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1; @@ -115,20 +117,22 @@ public: inline uint64_t expiration() const { return _expiration; } /** - * 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 + * @return Timestamp + */ + inline uint64_t timestamp() const { return _ts; } + + /** + * @return Last 'to' address in chain of custody */ - inline bool wasIssuedTo(const Address &a) const + inline Address issuedTo() const { + Address i2; for(unsigned int i=0;i(p); p += 4; _nwid = b.template at(p); p += 8; + _ts = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; + _id = b.template at(p); p += 4; deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES); _maxCustodyChainLength = (unsigned int)b[p++]; if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) throw std::runtime_error("invalid max custody chain length"); - for(unsigned int i;;++i) { + for(unsigned int i=0;;++i) { const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (!to) break; @@ -409,6 +415,7 @@ public: private: uint64_t _nwid; + uint64_t _ts; uint64_t _expiration; uint32_t _id; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c2df7ee2..29d0964c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -437,8 +437,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p 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); - LockingPtr m(peer->membership(com.networkId(),true)); - if (m) m->addCredential(RR,RR->node->now(),com); + if (com) { + SharedPtr network(RR->node->network(com.networkId())); + if (network) + network->addCredential(com); + } } if ((flags & 0x02) != 0) { @@ -567,8 +570,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

m(peer->membership(com.networkId(),true)); - if (m) m->addCredential(RR,RR->node->now(),com); + if (com) + network->addCredential(com); } if (!network->isAllowed(peer)) { @@ -661,7 +664,6 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const uint64_t now = RR->node->now(); CertificateOfMembership com; Capability cap; Tag tag; @@ -669,9 +671,13 @@ 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); - LockingPtr m(peer->membership(com.networkId(),true)); - if (!m) return true; // sanity check - if (m->addCredential(RR,now,com) == 1) return false; // wait for WHOIS + if (com) { + SharedPtr network(RR->node->network(com.networkId())); + if (network) { + if (network->addCredential(com) == 1) + return false; // wait for WHOIS + } + } } ++p; // skip trailing 0 after COMs if present @@ -679,17 +685,21 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i m(peer->membership(cap.networkId(),true)); - if (!m) return true; // sanity check - if (m->addCredential(RR,now,cap) == 1) return false; // wait for WHOIS + SharedPtr network(RR->node->network(cap.networkId())); + if (network) { + if (network->addCredential(cap) == 1) + return false; // wait for WHOIS + } } const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i m(peer->membership(tag.networkId(),true)); - if (!m) return true; // sanity check - if (m->addCredential(RR,now,tag) == 1) return false; // wait for WHOIS + SharedPtr network(RR->node->network(tag.networkId())); + if (network) { + if (network->addCredential(tag) == 1) + return false; // wait for WHOIS + } } } @@ -830,8 +840,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((flags & 0x01) != 0) { // deprecated but still used by older peers CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - LockingPtr m(peer->membership(com.networkId(),true)); - if (m) m->addCredential(RR,RR->node->now(),com); + if (com) + network->addCredential(com); } // Check membership after we've read any included COM, since @@ -1037,17 +1047,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt NetworkConfig originatorCredentialNetworkConfig; if (originatorCredentialNetworkId) { if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) { - SharedPtr nw(RR->node->network(originatorCredentialNetworkId)); - if ((nw)&&(nw->hasConfig())) { - originatorCredentialNetworkConfig = nw->config(); - if ( ( (originatorCredentialNetworkConfig.isPublic()) || (peer->address() == originatorAddress) || ((originatorCredentialNetworkConfig.com)&&(previousHopCom)&&(originatorCredentialNetworkConfig.com.agreesWith(previousHopCom))) ) ) { - TRACE("CIRCUIT_TEST %.16llx received from hop %s(%s) and originator %s with valid network ID credential %.16llx (verified from originator and next hop)",testId,source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and previous hop %s did not supply a valid COM",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId,peer->address().toString().c_str()); - return true; - } - } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + if (!RR->node->network(originatorCredentialNetworkId)) { + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member of that network",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); return true; } } else { diff --git a/node/Membership.cpp b/node/Membership.cpp index 79b1e1bc..e12bce3c 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -79,19 +79,19 @@ bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint return false; } -int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com) +int Membership::addCredential(const RuntimeEnvironment *RR,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) + if ((vr == 0)&&(com.revision() > _com.revision())) _com = com; return vr; } -int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag) +int Membership::addCredential(const RuntimeEnvironment *RR,const Tag &tag) { if (tag.issuedTo() != RR->identity.address()) return -1; @@ -102,15 +102,17 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,co if (vr == 0) { if (!t) t = &(_tags[tag.id()]); - t->lastReceived = now; - t->tag = tag; + if (t->tag.timestamp() <= tag.timestamp()) { + t->lastReceived = RR->node->now(); + t->tag = tag; + } } return vr; } -int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap) +int Membership::addCredential(const RuntimeEnvironment *RR,const Capability &cap) { - if (!cap.wasIssuedTo(RR->identity.address())) + if (cap.issuedTo() != RR->identity.address()) return -1; std::map::iterator c(_caps.find(cap.id())); if ((c != _caps.end())&&(c->second.lastReceived != 0)&&(c->second.cap == cap)) @@ -119,10 +121,10 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,co if (vr == 0) { if (c == _caps.end()) { CState &c2 = _caps[cap.id()]; - c2.lastReceived = now; + c2.lastReceived = RR->node->now(); c2.cap = cap; - } else { - c->second.lastReceived = now; + } else if (c->second.cap.timestamp() <= cap.timestamp()) { + c->second.lastReceived = RR->node->now(); c->second.cap = cap; } } diff --git a/node/Membership.hpp b/node/Membership.hpp index 664cd2ad..e9f9d488 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -180,21 +180,21 @@ public: * * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com); + int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com); /** * 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 */ - int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag); + int addCredential(const RuntimeEnvironment *RR,const Tag &tag); /** * 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 */ - int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap); + int addCredential(const RuntimeEnvironment *RR,const Capability &cap); /** * Clean up old or stale entries diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index e1d4567a..9e583e34 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -152,7 +152,6 @@ std::vector

Multicaster::getMembers(uint64_t nwid,const MulticastGroup } void Multicaster::send( - const CertificateOfMembership *com, unsigned int limit, uint64_t now, uint64_t nwid, @@ -194,7 +193,6 @@ void Multicaster::send( RR, now, nwid, - com, limit, 1, // we'll still gather a little from peers to keep multicast list fresh src, @@ -236,22 +234,12 @@ void Multicaster::send( if (!p) continue; //TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str()); - - const CertificateOfMembership *com = (CertificateOfMembership *)0; - { - SharedPtr nw(RR->node->network(nwid)); - if ((nw)&&(nw->hasConfig())&&(nw->config().com)&&(nw->config().isPrivate())&&(p->needsOurNetworkMembershipCertificate(nwid,now,true))) - com = &(nw->config().com); - } - Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER); outp.append(nwid); - outp.append((uint8_t)(com ? 0x01 : 0x00)); + outp.append((uint8_t)0x00); mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); outp.append((uint32_t)gatherLimit); - if (com) - com->serialize(outp); RR->sw->send(outp,true,0); } gatherLimit = 0; @@ -264,7 +252,6 @@ void Multicaster::send( RR, now, nwid, - com, limit, gatherLimit, src, diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index c43c8d93..51dabc69 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -150,7 +150,6 @@ public: /** * Send a multicast * - * @param com Certificate of membership to include or NULL for none * @param limit Multicast limit * @param now Current time * @param nwid Network ID @@ -162,7 +161,6 @@ public: * @param len Length of packet data */ void send( - const CertificateOfMembership *com, unsigned int limit, uint64_t now, uint64_t nwid, diff --git a/node/Network.cpp b/node/Network.cpp index a8165d3e..fd2fac2b 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -348,7 +348,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : _netconfFailure(NETCONF_FAILURE_NONE), _portError(0) { - char confn[128],mcdbn[128]; + char confn[128]; Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id); if (_id == ZT_TEST_NETWORK_ID) { diff --git a/node/Network.hpp b/node/Network.hpp index 06fd7735..16f07163 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -336,6 +336,42 @@ public: */ void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now); + /** + * @param com Certificate of membership + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const CertificateOfMembership &com) + { + if (com.networkId() != _id) + return -1; + Mutex::Lock _l(_lock); + return _memberships[com.issuedTo()].addCredential(RR,com); + } + + /** + * @param cap Capability + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const Capability &cap) + { + if (cap.networkId() != _id) + return -1; + Mutex::Lock _l(_lock); + return _memberships[cap.issuedTo()].addCredential(RR,cap); + } + + /** + * @param cap Tag + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + inline int addCredential(const Tag &tag) + { + if (tag.networkId() != _id) + return -1; + Mutex::Lock _l(_lock); + return _memberships[tag.issuedTo()].addCredential(RR,tag); + } + /** * Destroy this network * diff --git a/node/Packet.cpp b/node/Packet.cpp index 4aebf6a9..eda60757 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -22,7 +22,7 @@ namespace ZeroTier { const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -//#ifdef ZT_TRACE +#ifdef ZT_TRACE const char *Packet::verbString(Verb v) throw() @@ -60,14 +60,13 @@ const char *Packet::errorString(ErrorCode e) case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; - case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; } return "(unknown)"; } -//#endif // ZT_TRACE +#endif // ZT_TRACE void Packet::armor(const void *key,bool encryptPayload) { diff --git a/node/Packet.hpp b/node/Packet.hpp index 6789580e..dce9f208 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1060,12 +1060,12 @@ public: ERROR_UNWANTED_MULTICAST = 0x08 }; -//#ifdef ZT_TRACE +#ifdef ZT_TRACE static const char *verbString(Verb v) throw(); static const char *errorString(ErrorCode e) throw(); -//#endif +#endif template Packet(const Buffer &b) : diff --git a/node/Peer.cpp b/node/Peer.cpp index ba47a0be..89dce570 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -53,9 +53,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _id(peerIdentity), _numPaths(0), _latency(0), - _directPathPushCutoffCount(0), - _networkComs(4), - _lastPushedComs(4) + _directPathPushCutoffCount(0) { if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); diff --git a/node/Switch.cpp b/node/Switch.cpp index 33b08429..167c7928 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -35,7 +35,6 @@ #include "Peer.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" -#include "Filter.hpp" #include "Cluster.hpp" namespace ZeroTier { @@ -438,26 +437,12 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len); - if (!Filter::run( - RR, - network->id(), - RR->identity.address(), - Address(), // 0 destination ZT address for multicasts since this is unknown at time of send - from, - to, - (const uint8_t *)data, - len, - etherType, - vlanId, - network->config().rules, - network->config().ruleCount)) - { - TRACE("%.16llx: %s -> %s %s packet not sent: Filter::run() == false (multicast)",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + if (!network->filterOutgoingPacket(RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { + TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } RR->mc->send( - ((!network->config().isPublic())&&(network->config().com)) ? &(network->config().com) : (const CertificateOfMembership *)0, network->config().multicastLimit, RR->node->now(), network->id(), @@ -477,34 +462,15 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this SharedPtr toPeer(RR->topology->getPeer(toZT)); - if (!Filter::run( - RR, - network->id(), - RR->identity.address(), - toZT, - from, - to, - (const uint8_t *)data, - len, - etherType, - vlanId, - network->config().rules, - network->config().ruleCount)) - { - TRACE("%.16llx: %s -> %s %s packet not sent: Filter::run() == false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + if (!network->filterOutgoingPacket(RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { + TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } - const bool includeCom = ( (network->config().isPrivate()) && (network->config().com) && ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ); - if ((fromBridged)||(includeCom)) { + if (fromBridged) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - if (includeCom) { - outp.append((unsigned char)0x01); // 0x01 -- COM included - network->config().com.serialize(outp); - } else { - outp.append((unsigned char)0x00); - } + outp.append((unsigned char)0x00); to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); @@ -564,12 +530,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c SharedPtr bridgePeer(RR->topology->getPeer(bridges[b])); Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - if ( (network->config().isPrivate()) && (network->config().com) && ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ) { - outp.append((unsigned char)0x01); // 0x01 -- COM included - network->config().com.serialize(outp); - } else { - outp.append((unsigned char)0); - } + outp.append((uint8_t)0x00); to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); diff --git a/node/Tag.hpp b/node/Tag.hpp index a9f6f57e..b4bc63c4 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -61,13 +61,15 @@ public: /** * @param nwid Network ID + * @param ts Timestamp * @param expiration Tag expiration relative to network config timestamp * @param issuedTo Address to which this tag was issued * @param id Tag ID * @param value Tag value */ - Tag(const uint64_t nwid,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) : + Tag(const uint64_t nwid,const uint64_t ts,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) : _nwid(nwid), + _ts(ts), _expiration(expiration), _id(id), _value(value), @@ -78,6 +80,7 @@ public: inline uint64_t networkId() const { return _nwid; } inline uint64_t expiration() const { return _expiration; } + inline uint64_t timestamp() const { return _ts; } inline uint32_t id() const { return _id; } inline const uint32_t &value() const { return _value; } inline const Address &issuedTo() const { return _issuedTo; } @@ -115,6 +118,7 @@ public: if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append(_nwid); + b.append(_ts); b.append(_expiration); b.append(_id); b.append(_value); @@ -136,6 +140,7 @@ public: unsigned int p = startAt; _nwid = b.template at(p); p += 8; + _ts = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; _id = b.template at(p); p += 4; _value = b.template at(p); p += 4; @@ -163,6 +168,7 @@ public: private: uint64_t _nwid; + uint64_t _ts; uint64_t _expiration; uint32_t _id; uint32_t _value; diff --git a/node/Topology.cpp b/node/Topology.cpp index ef1c1698..6e0fe90c 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -74,34 +74,6 @@ Topology::Topology(const RuntimeEnvironment *renv) : Topology::~Topology() { - Buffer *pbuf = 0; - try { - pbuf = new Buffer(); - std::string all; - - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - Hashtable< Address,SharedPtr >::Iterator i(_peers); - while (i.next(a,p)) { - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) { - pbuf->clear(); - try { - (*p)->serialize(*pbuf); - try { - all.append((const char *)pbuf->data(),pbuf->size()); - } catch ( ... ) { - return; // out of memory? just skip - } - } catch ( ... ) {} // peer too big? shouldn't happen, but it so skip - } - } - - RR->node->dataStorePut("peers.save",all,true); - - delete pbuf; - } catch ( ... ) { - delete pbuf; - } } SharedPtr Topology::addPeer(const SharedPtr &peer) -- cgit v1.2.3 From e1310a764a39d0ed1f29f213c6e75c4e2d7a8aba Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 9 Aug 2016 15:45:26 -0700 Subject: More cleanup and removal of cruft due to obsolete network-specific relays (will be replaced with federation stuff). --- node/IncomingPacket.cpp | 16 ++++++---- node/Membership.cpp | 2 +- node/Multicaster.cpp | 2 +- node/Network.cpp | 8 ++--- node/Node.cpp | 4 +-- node/OutboundMulticast.cpp | 2 +- node/Peer.cpp | 8 ++--- node/Peer.hpp | 3 +- node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 76 ++++++---------------------------------------- node/Switch.hpp | 42 ++----------------------- 11 files changed, 37 insertions(+), 128 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b6ec2d3f..df224c19 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -510,9 +510,13 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) - RR->sw->rendezvous(withPeer,_localAddress,atAddr); + TRACE("RENDEZVOUS from %s says %s might be at %s, attempting to contact",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { + const uint64_t now = RR->node->now(); + peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) + if (!peer->pushDirectPaths(_localAddress,atAddr,now,true)) + peer->sendHELLO(_localAddress,atAddr,now); + } } else { TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -746,7 +750,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((uint32_t)totalSize); outp.append((uint32_t)chunkIndex); outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); chunkIndex += chunkLen; } } @@ -1139,7 +1143,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt nextHop[h].appendTo(outp); nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress } - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } // If there are next hops, forward the test along through the graph @@ -1154,7 +1158,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid outp.newInitializationVector(); outp.setDestination(nextHop[h]); - RR->sw->send(outp,true,originatorCredentialNetworkId); + RR->sw->send(outp,true); } } } diff --git a/node/Membership.cpp b/node/Membership.cpp index e12bce3c..dbba7f0d 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -69,7 +69,7 @@ bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint outp.append((uint8_t)0x00); outp.append(capsAndTags.data(),capsAndTags.size()); outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); _lastPushedCom = now; return true; } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 9e583e34..aeee0a85 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -240,7 +240,7 @@ void Multicaster::send( mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); outp.append((uint32_t)gatherLimit); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } gatherLimit = 0; } diff --git a/node/Network.cpp b/node/Network.cpp index b84756aa..e098c1fd 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -127,7 +127,7 @@ static int _doZtFilter( outp.append((uint16_t)etherType); outp.append(frameData,frameLen); outp.compress(); - RR->sw->send(outp,true,nwid); + RR->sw->send(outp,true); if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { return -1; // match, drop packet (we redirected it) @@ -678,7 +678,7 @@ void Network::requestConfiguration() outp.append((const void *)rmd.data(),rmdSize); outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0); outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); // Expect replies with this in-re packet ID _inboundConfigPacketId = outp.packetId(); @@ -894,7 +894,7 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } @@ -906,7 +906,7 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } } diff --git a/node/Node.cpp b/node/Node.cpp index f04559db..4da79347 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -237,7 +237,7 @@ public: // way whatsoever. This will e.g. find network preferred relays that lack // stable endpoints by using root servers. Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); @@ -520,7 +520,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[0].breadth;++a) { outp.newInitializationVector(); outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index a5856164..c9952927 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -90,7 +90,7 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr); - RR->sw->send(_packet,true,_nwid); + RR->sw->send(_packet,true); } } diff --git a/node/Peer.cpp b/node/Peer.cpp index 89dce570..77e1d0b5 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -241,7 +241,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) return false; } -bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force,bool includePrivatePaths) +bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force) { #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection @@ -258,10 +258,8 @@ bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAdd std::vector pathsToPush; std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) { - if ((includePrivatePaths)||(i->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) - pathsToPush.push_back(*i); - } + for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) + pathsToPush.push_back(*i); std::vector sym(RR->sa->getSymmetricNatPredictions()); for(unsigned long i=0,added=0;i >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->activelyTransferringFrames(now)) { Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true,0); + RR->sw->send(outp,true); } } } else { diff --git a/node/Switch.cpp b/node/Switch.cpp index 167c7928..37daff27 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -476,14 +476,14 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append((uint16_t)etherType); outp.append(data,len); outp.compress(); - send(outp,true,network->id()); + send(outp,true); } else { Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); outp.append((uint16_t)etherType); outp.append(data,len); outp.compress(); - send(outp,true,network->id()); + send(outp,true); } //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); @@ -536,23 +536,21 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append((uint16_t)etherType); outp.append(data,len); outp.compress(); - send(outp,true,network->id()); + send(outp,true); } } } -void Switch::send(const Packet &packet,bool encrypt,uint64_t nwid) +void Switch::send(const Packet &packet,bool encrypt) { if (packet.destination() == RR->identity.address()) { TRACE("BUG: caught attempt to send() to self, ignored"); return; } - //TRACE(">> %s to %s (%u bytes, encrypt==%d, nwid==%.16llx)",Packet::verbString(packet.verb()),packet.destination().toString().c_str(),packet.size(),(int)encrypt,nwid); - - if (!_trySend(packet,encrypt,nwid)) { + if (!_trySend(packet,encrypt)) { Mutex::Lock _l(_txQueue_m); - _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt,nwid)); + _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); } } @@ -625,17 +623,6 @@ bool Switch::unite(const Address &p1,const Address &p2) return true; } -void Switch::rendezvous(const SharedPtr &peer,const InetAddress &localAddr,const InetAddress &atAddr) -{ - TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); - const uint64_t now = RR->node->now(); - peer->sendHELLO(localAddr,atAddr,now,2); // first attempt: send low-TTL packet to 'open' local NAT - { - Mutex::Lock _l(_contactQueue_m); - _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,localAddr,atAddr)); - } -} - void Switch::requestWhois(const Address &addr) { bool inserted = false; @@ -676,7 +663,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(txi->packet,txi->encrypt,txi->nwid)) + if (_trySend(txi->packet,txi->encrypt)) _txQueue.erase(txi++); else ++txi; } else ++txi; @@ -688,42 +675,6 @@ unsigned long Switch::doTimerTasks(uint64_t now) { unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - { // Iterate through NAT traversal strategies for entries in contact queue - Mutex::Lock _l(_contactQueue_m); - for(std::list::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { - if (now >= qi->fireAtTime) { - if (!qi->peer->pushDirectPaths(qi->localAddr,qi->inaddr,now,true,false)) - qi->peer->sendHELLO(qi->localAddr,qi->inaddr,now); - _contactQueue.erase(qi++); - continue; - /* Old symmetric NAT buster code, obsoleted by port prediction alg in SelfAwareness but left around for now in case we revert - if (qi->strategyIteration == 0) { - // First strategy: send packet directly to destination - qi->peer->sendHELLO(qi->localAddr,qi->inaddr,now); - } else if (qi->strategyIteration <= 3) { - // Strategies 1-3: try escalating ports for symmetric NATs that remap sequentially - InetAddress tmpaddr(qi->inaddr); - int p = (int)qi->inaddr.port() + qi->strategyIteration; - if (p > 65535) - p -= 64511; - tmpaddr.setPort((unsigned int)p); - qi->peer->sendHELLO(qi->localAddr,tmpaddr,now); - } else { - // All strategies tried, expire entry - _contactQueue.erase(qi++); - continue; - } - ++qi->strategyIteration; - qi->fireAtTime = now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY; - nextDelay = std::min(nextDelay,(unsigned long)ZT_NAT_T_TACTICAL_ESCALATION_DELAY); - */ - } else { - nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now)); - } - ++qi; // if qi was erased, loop will have continued before here - } - } - { // Retry outstanding WHOIS requests Mutex::Lock _l(_outstandingWhoisRequests_m); Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests); @@ -751,7 +702,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(txi->packet,txi->encrypt,txi->nwid)) + if (_trySend(txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); @@ -787,20 +738,13 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread return Address(); } -bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) +bool Switch::_trySend(const Packet &packet,bool encrypt) { SharedPtr peer(RR->topology->getPeer(packet.destination())); if (peer) { const uint64_t now = RR->node->now(); - SharedPtr network; - if (nwid) { - network = RR->node->network(nwid); - if ((!network)||(!network->hasConfig())) - return false; // we probably just left this network, let its packets die - } - Path *viaPath = peer->getBestPath(now); SharedPtr relay; @@ -811,7 +755,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) } if (relay) { - peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false,( (network)&&(network->isAllowed(peer)) )); + peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false); viaPath->sent(now); } diff --git a/node/Switch.hpp b/node/Switch.hpp index ce4f00a1..7c903ef9 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -92,15 +92,10 @@ public: * Needless to say, the packet's source must be this node. Otherwise it * won't be encrypted right. (This is not used for relaying.) * - * The network ID should only be specified for frames and other actual - * network traffic. Other traffic such as controller requests and regular - * protocol messages should specify zero. - * * @param packet Packet to send * @param encrypt Encrypt packet payload? (always true except for HELLO) - * @param nwid Related network ID or 0 if message is not in-network traffic */ - void send(const Packet &packet,bool encrypt,uint64_t nwid); + void send(const Packet &packet,bool encrypt); /** * Send RENDEZVOUS to two peers to permit them to directly connect @@ -113,15 +108,6 @@ public: */ bool unite(const Address &p1,const Address &p2); - /** - * Attempt NAT traversal to peer at a given physical address - * - * @param peer Peer to contact - * @param localAddr Local interface address - * @param atAddr Address of peer - */ - void rendezvous(const SharedPtr &peer,const InetAddress &localAddr,const InetAddress &atAddr); - /** * Request WHOIS on a given address * @@ -151,7 +137,7 @@ public: private: Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); - bool _trySend(const Packet &packet,bool encrypt,uint64_t nwid); + bool _trySend(const Packet &packet,bool encrypt); const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; @@ -205,16 +191,14 @@ private: struct TXQueueEntry { TXQueueEntry() {} - TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,uint64_t nw) : + TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc) : dest(d), creationTime(ct), - nwid(nw), packet(p), encrypt(enc) {} Address dest; uint64_t creationTime; - uint64_t nwid; Packet packet; // unencrypted/unMAC'd packet -- this is done at send time bool encrypt; }; @@ -241,26 +225,6 @@ private: }; Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior Mutex _lastUniteAttempt_m; - - // Active attempts to contact remote peers, including state of multi-phase NAT traversal - struct ContactQueueEntry - { - ContactQueueEntry() {} - ContactQueueEntry(const SharedPtr &p,uint64_t ft,const InetAddress &laddr,const InetAddress &a) : - peer(p), - fireAtTime(ft), - inaddr(a), - localAddr(laddr), - strategyIteration(0) {} - - SharedPtr peer; - uint64_t fireAtTime; - InetAddress inaddr; - InetAddress localAddr; - unsigned int strategyIteration; - }; - std::list _contactQueue; - Mutex _contactQueue_m; }; } // namespace ZeroTier -- cgit v1.2.3 From c476285bd638da01e0297c76951609c70f4ab3cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 24 Aug 2016 16:16:39 -0700 Subject: Harden PUSH_DIRECT_PATHS and simplify things by only doing it on receive when hops>0 and trust has been established. --- node/IncomingPacket.cpp | 78 ++++++++++++---------- node/Peer.cpp | 171 ++++++++++++++++++++++++------------------------ node/Peer.hpp | 18 ++--- node/Switch.cpp | 5 -- 4 files changed, 135 insertions(+), 137 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1aecfdb7..8faa62fb 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -88,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; case Packet::VERB_HELLO: return _doHELLO(RR,peer); @@ -172,7 +172,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -339,7 +339,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -461,7 +461,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -505,7 +505,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -527,8 +527,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } else if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { const uint64_t now = RR->node->now(); peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) - if (!peer->pushDirectPaths(_localAddress,atAddr,now,true)) - peer->sendHELLO(_localAddress,atAddr,now); + peer->sendHELLO(_localAddress,atAddr,now); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -540,7 +539,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -555,19 +554,17 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr 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()); - return true; - } - - const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),network->id()); - const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) { - RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); + } else { + const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + const MAC sourceMac(peer->address(),network->id()); + const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) + RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); } } - - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP); } else { TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -595,6 +592,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

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()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -608,6 +606,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -616,24 +615,24 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - - if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { + if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); - } - } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + } } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -654,7 +653,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -673,7 +672,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -722,7 +721,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -740,7 +739,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); if (RR->localNetworkController) { NetworkConfig *netconf = new NetworkConfig(); @@ -899,7 +898,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -929,6 +928,7 @@ 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()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -955,10 +955,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -967,6 +969,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -990,9 +993,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } - } // else ignore -- not a member of this network - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + } else { + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1007,6 +1012,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // First, subject this to a rate limit if (!peer->shouldRespondToDirectPathPush(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1069,7 +1075,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1113,6 +1119,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1129,10 +1136,12 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1203,7 +1212,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1248,6 +1257,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S } RR->node->postCircuitTestReport(&report); + peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -1308,7 +1318,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const break; } - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP); + peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); } else { TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 77e1d0b5..7691408e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -66,7 +66,8 @@ void Peer::received( uint64_t packetId, Packet::Verb verb, uint64_t inRePacketId, - Packet::Verb inReVerb) + Packet::Verb inReVerb, + const bool trustEstablished) { #ifdef ZT_ENABLE_CLUSTER bool suboptimalPath = false; @@ -184,6 +185,8 @@ void Peer::received( } } + } else if (trustEstablished) { + _pushDirectPaths(localAddr,remoteAddr,now); } if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { @@ -241,90 +244,6 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) return false; } -bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force) -{ -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - if (RR->cluster) - return false; -#endif - - if (!force) { - if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL) - return false; - else _lastDirectPathPushSent = now; - } - - std::vector pathsToPush; - - std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) - pathsToPush.push_back(*i); - - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; - } - } - if (pathsToPush.empty()) - return false; - -#ifdef ZT_TRACE - { - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); - } -#endif - - std::vector::const_iterator p(pathsToPush.begin()); - while (p != pathsToPush.end()) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.addSize(2); // leave room for count - - unsigned int count = 0; - while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { - uint8_t addressType = 4; - switch(p->ss_family) { - case AF_INET: - break; - case AF_INET6: - addressType = 6; - break; - default: // we currently only push IP addresses - ++p; - continue; - } - - outp.append((uint8_t)0); // no flags - outp.append((uint16_t)0); // no extensions - outp.append(addressType); - outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->port()); - - ++count; - ++p; - } - - if (count) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true); - RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0); - } - } - - return true; -} - bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) { unsigned int np = _numPaths; @@ -453,4 +372,86 @@ Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) return bestPath; } +bool Peer::_pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now) +{ +#ifdef ZT_ENABLE_CLUSTER + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + if (RR->cluster) + return false; +#endif + + if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL) + return false; + else _lastDirectPathPushSent = now; + + std::vector pathsToPush; + + std::vector dps(RR->node->directPaths()); + for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) + pathsToPush.push_back(*i); + + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } + } + if (pathsToPush.empty()) + return false; + +#ifdef ZT_TRACE + { + std::string ps; + for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { + if (ps.length() > 0) + ps.push_back(','); + ps.append(p->toString()); + } + TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); + } +#endif + + std::vector::const_iterator p(pathsToPush.begin()); + while (p != pathsToPush.end()) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); + outp.addSize(2); // leave room for count + + unsigned int count = 0; + while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { + uint8_t addressType = 4; + switch(p->ss_family) { + case AF_INET: + break; + case AF_INET6: + addressType = 6; + break; + default: // we currently only push IP addresses + ++p; + continue; + } + + outp.append((uint8_t)0); // no flags + outp.append((uint16_t)0); // no extensions + outp.append(addressType); + outp.append((uint8_t)((addressType == 4) ? 6 : 18)); + outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); + outp.append((uint16_t)p->port()); + + ++count; + ++p; + } + + if (count) { + outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); + outp.armor(_key,true); + RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0); + } + } + + return true; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 200c5ac4..a6940737 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -104,6 +104,7 @@ public: * @param verb Packet verb * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) + * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established */ void received( const InetAddress &localAddr, @@ -111,8 +112,9 @@ public: unsigned int hops, uint64_t packetId, Packet::Verb verb, - uint64_t inRePacketId = 0, - Packet::Verb inReVerb = Packet::VERB_NOP); + uint64_t inRePacketId, + Packet::Verb inReVerb, + const bool trustEstablished); /** * Get the current best direct path to this peer @@ -192,17 +194,6 @@ public: */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); - /** - * Push direct paths back to self if we haven't done so in the configured timeout - * - * @param localAddr Local address - * @param toAddress Remote address to send push to (usually from path) - * @param now Current time - * @param force If true, push regardless of rate limit - * @return True if something was actually sent - */ - bool pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force); - /** * @return All known direct paths to this peer (active or inactive) */ @@ -407,6 +398,7 @@ private: void _doDeadPathDetection(Path &p,const uint64_t now); Path *_getBestPath(const uint64_t now); Path *_getBestPath(const uint64_t now,int inetAddressFamily); + bool _pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; diff --git a/node/Switch.cpp b/node/Switch.cpp index f6e4d1ab..546c9157 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -761,11 +761,6 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) return false; } - if (relay) { - peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false); - viaPath->sent(now); - } - Packet tmp(packet); unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); -- cgit v1.2.3 From 584228b2b5ff91a3db4699174bbefe1540d4ce59 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 24 Aug 2016 17:56:35 -0700 Subject: Dead code removal, and get rid of reliable() because we will no longer make that distinction. --- node/Path.hpp | 42 ------------------------------------------ node/Peer.cpp | 4 +--- 2 files changed, 1 insertion(+), 45 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Path.hpp b/node/Path.hpp index ecf4be24..ca5dd98f 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -247,16 +247,6 @@ public: return score; } - /** - * @return True if path is considered reliable (no NAT keepalives etc. are needed) - */ - inline bool reliable() const throw() - { - if ((_addr.ss_family == AF_INET)||(_addr.ss_family == AF_INET6)) - return ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE)); - return true; - } - /** * @return True if address is non-NULL */ @@ -313,38 +303,6 @@ public: */ inline void increaseProbation() { ++_probation; } - template - inline void serialize(Buffer &b) const - { - b.append((uint8_t)2); // version - b.append((uint64_t)_lastSend); - b.append((uint64_t)_lastPing); - b.append((uint64_t)_lastKeepalive); - b.append((uint64_t)_lastReceived); - _addr.serialize(b); - _localAddress.serialize(b); - b.append((uint16_t)_flags); - b.append((uint16_t)_probation); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - if (b[p++] != 2) - throw std::invalid_argument("invalid serialized Path"); - _lastSend = b.template at(p); p += 8; - _lastPing = b.template at(p); p += 8; - _lastKeepalive = b.template at(p); p += 8; - _lastReceived = b.template at(p); p += 8; - p += _addr.deserialize(b,p); - p += _localAddress.deserialize(b,p); - _flags = b.template at(p); p += 2; - _probation = b.template at(p); p += 2; - _ipScope = _addr.ipScope(); - return (p - startAt); - } - inline bool operator==(const Path &p) const { return ((p._addr == _addr)&&(p._localAddress == _localAddress)); } inline bool operator!=(const Path &p) const { return ((p._addr != _addr)||(p._localAddress != _localAddress)); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 7691408e..01492be1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -230,13 +230,11 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) sendHELLO(p->localAddress(),p->address(),now); p->sent(now); p->pinged(now); - } else if ( ((now - std::max(p->lastSend(),p->lastKeepalive())) >= ZT_NAT_KEEPALIVE_DELAY) && (!p->reliable()) ) { + } else if ((now - std::max(p->lastSend(),p->lastKeepalive())) >= ZT_NAT_KEEPALIVE_DELAY) { //TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); p->sentKeepalive(now); - } else { - //TRACE("no PING or NAT keepalive: addr==%s reliable==%d %llums/%llums send/receive inactivity",p->address().toString().c_str(),(int)p->reliable(),now - p->lastSend(),now - p->lastReceived()); } return true; } -- cgit v1.2.3 From e8f6b4b5d33e7b762b952d599e8cc9e730b21c03 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 11:51:33 -0700 Subject: Rest of big Path canonicalization refactor. --- node/Constants.hpp | 36 ++--- node/IncomingPacket.cpp | 290 ++++++++++++++++++++-------------------- node/Node.cpp | 18 +-- node/Path.hpp | 82 ++++-------- node/Peer.cpp | 348 ++++++++++++++++++++++++++---------------------- node/Peer.hpp | 166 ++++++++++------------- node/Switch.cpp | 24 ++-- 7 files changed, 461 insertions(+), 503 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 8a596fb3..6d6f44e0 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -238,46 +238,38 @@ */ #define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000 -/** - * Default maximum number of peers to address with a single multicast (if unspecified in network config) - */ -#define ZT_MULTICAST_DEFAULT_LIMIT 32 - -/** - * How frequently to send a zero-byte UDP keepalive packet - * - * There are NATs with timeouts as short as 20 seconds, so this turns out - * to be needed. - */ -#define ZT_NAT_KEEPALIVE_DELAY 19000 - /** * Delay between scans of the topology active peer DB for peers that need ping * * This is also how often pings will be retried to upstream peers (relays, roots) * constantly until something is heard. */ -#define ZT_PING_CHECK_INVERVAL 9500 +#define ZT_PING_CHECK_INVERVAL 8000 /** - * Delay between ordinary case pings of direct links + * How frequently to send heartbeats over in-use paths */ -#define ZT_PEER_DIRECT_PING_DELAY 60000 +#define ZT_PATH_HEARTBEAT_PERIOD 18000 /** - * Timeout for overall peer activity (measured from last receive) + * Paths are considered inactive if they have not received traffic in this long */ -#define ZT_PEER_ACTIVITY_TIMEOUT 500000 +#define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_HEARTBEAT_PERIOD * 2) + 2000) /** - * No answer timeout to trigger dead path detection + * Delay between full-fledge pings of directly connected peers */ -#define ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT 2000 +#define ZT_PEER_PING_PERIOD 60000 /** - * Probation threshold after which a path becomes dead + * Peers forget paths that have not spoken in this long */ -#define ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION 3 +#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 3) + 3000) + +/** + * Timeout for overall peer activity (measured from last receive) + */ +#define ZT_PEER_ACTIVITY_TIMEOUT 500000 /** * Delay between requests for updated network autoconf information diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 4b013078..fafd5679 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -54,11 +54,11 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) // If this is marked as a packet via a trusted path, check source address and path ID. // Obviously if no trusted paths are configured this always returns false and such // packets are dropped on the floor. - if (RR->topology->shouldInboundPathBeTrusted(_remoteAddress,trustedPathId())) { + if (RR->topology->shouldInboundPathBeTrusted(_path->address(),trustedPathId())) { trusted = true; - TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId()); + TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId()); } else { - TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId(),_remoteAddress.toString().c_str()); + TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId(),_path->address().toString().c_str()); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -73,42 +73,42 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { - TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),size()); + TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); return true; } } if (!uncompress()) { - TRACE("dropped packet from %s(%s), compressed data invalid",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped packet from %s(%s), compressed data invalid",sourceAddress.toString().c_str(),_path->address().toString().c_str()); return true; } const Packet::Verb v = verb(); - //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_path->address().toString().c_str()); switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,peer); - case Packet::VERB_ERROR: return _doERROR(RR,peer); - case Packet::VERB_OK: return _doOK(RR,peer); - case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); - case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer); - case Packet::VERB_FRAME: return _doFRAME(RR,peer); - 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_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); - case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); - case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); - case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); - case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); - case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); - case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer); + case Packet::VERB_HELLO: return _doHELLO(RR,peer); + case Packet::VERB_ERROR: return _doERROR(RR,peer); + case Packet::VERB_OK: return _doOK(RR,peer); + case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); + case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer); + case Packet::VERB_FRAME: return _doFRAME(RR,peer); + 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_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); + case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); + case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); + case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); + case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); + case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); + case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); + case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); + case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer); case Packet::VERB_USER_MESSAGE: return true; } @@ -119,7 +119,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } catch ( ... ) { // Exceptions are more informatively caught in _do...() handlers but // this outer try/catch will catch anything else odd. - TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_path->address().toString().c_str()); return true; } } @@ -131,7 +131,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); + //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(errorCode) { @@ -172,9 +172,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -216,11 +216,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; } @@ -235,18 +235,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_path->address().toString().c_str()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_HELLO); outp.append((uint64_t)pid); outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); } } else { - TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_path->address().toString().c_str()); } return true; @@ -254,7 +254,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } @@ -265,14 +265,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // Check identity proof of work if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } // Check packet integrity and authentication SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); return true; } peer = RR->topology->addPeer(newPeer); @@ -284,7 +284,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } if (externalSurfaceAddress) - RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); + RR->sa->iam(id.address(),_path->localAddress(),_path->address(),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); @@ -295,7 +295,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); if (protoVersion >= 5) { - _remoteAddress.serialize(outp); + _path->address().serialize(outp); } else { /* LEGACY COMPATIBILITY HACK: * @@ -320,7 +320,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer * nulling out the port field. Since this info is only used for empirical * detection of link changes, it doesn't break anything else. */ - InetAddress tmpa(_remoteAddress); + InetAddress tmpa(_path->address()); tmpa.setPort(0); tmpa.serialize(outp); } @@ -336,12 +336,12 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -352,7 +352,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); + //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { @@ -364,7 +364,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); if (vProto < ZT_PROTO_VERSION_MIN) { - TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_path->address().toString().c_str()); return true; } @@ -386,13 +386,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } } - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if (externalSurfaceAddress) - RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: { @@ -414,7 +414,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p totalSize = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen); chunkIndex = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT + chunkLen + 4); } - TRACE("%s(%s): OK(NETWORK_CONFIG_REQUEST) chunkLen==%u chunkIndex==%u totalSize==%u",source().toString().c_str(),_remoteAddress.toString().c_str(),chunkLen,chunkIndex,totalSize); + TRACE("%s(%s): OK(NETWORK_CONFIG_REQUEST) chunkLen==%u chunkIndex==%u totalSize==%u",source().toString().c_str(),_path->address().toString().c_str(),chunkLen,chunkIndex,totalSize); network->handleInboundConfigChunk(inRePacketId,chunkData,chunkLen,chunkIndex,totalSize); } } break; @@ -425,7 +425,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),size()); + //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } break; @@ -435,7 +435,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),flags); + //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); unsigned int offset = 0; @@ -461,9 +461,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -502,12 +502,12 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr if (count > 0) { outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -524,24 +524,22 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (!RR->topology->isUpstream(peer->identity())) { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr)) { - const uint64_t now = RR->node->now(); - peer->sendHELLO(_localAddress,atAddr,now,2); // send low-TTL packet to 'open' local NAT(s) - peer->sendHELLO(_localAddress,atAddr,now); + } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { + RR->node->putPacket(_path->localAddress(),atAddr,"NATSUX",6,2); // send low-TTL packet to 'open' local NAT(s) + peer->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); } } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -553,8 +551,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr if (network) { 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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); } else { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); const MAC sourceMac(peer->address(),network->id()); @@ -562,14 +560,14 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); } } } else { - TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } } catch ( ... ) { - TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -591,8 +589,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -603,8 +601,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -614,14 +612,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -631,13 +629,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } } else { - TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } } catch ( ... ) { - TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -652,10 +650,10 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -672,9 +670,9 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -721,9 +719,9 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped NETWORK_CREDENTIALS 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(),_path->address().toString().c_str()); } return true; } @@ -744,7 +742,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons if (RR->localNetworkController) { NetworkConfig *netconf = new NetworkConfig(); try { - switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,*netconf)) { + switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) { case NetworkController::NETCONF_QUERY_OK: { netconfOk = true; @@ -783,7 +781,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } break; case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { @@ -793,7 +791,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } break; case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: @@ -816,16 +814,16 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_localAddress,_remoteAddress,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); + TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { fprintf(stderr,"WARNING: network config request failed with exception: unknown exception" ZT_EOL_S); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -840,8 +838,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons if (network) { network->requestConfiguration(); } else { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); return true; } @@ -853,9 +851,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -868,7 +866,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); if ((flags & 0x01) != 0) { try { @@ -880,7 +878,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar network->addCredential(com); } } catch ( ... ) { - TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); } } @@ -892,9 +890,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); - if (gatheredLocally) { + if (gatheredLocally > 0) { outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } // If we are a member of a cluster, distribute this GATHER across it @@ -904,9 +902,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -933,8 +931,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share // Check membership after we've read any included COM, since // 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()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -960,13 +958,13 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -974,8 +972,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -996,16 +994,16 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share outp.append((unsigned char)0x02); // flag 0x02 = contains gather results if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { - TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1017,8 +1015,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // First, subject this to a rate limit if (!peer->shouldRespondToDirectPathPush(now)) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1044,12 +1042,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimalPathForAddressFamily(a); + peer->makeExclusive(a); } else { redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->sendHELLO(InetAddress(),a,now); @@ -1063,12 +1061,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimalPathForAddressFamily(a); + peer->makeExclusive(a); } else { redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->sendHELLO(InetAddress(),a,now); @@ -1081,9 +1079,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1124,8 +1122,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt // Verify signature -- only tests signed by their originators are allowed const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { - TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1141,13 +1139,13 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (originatorCredentialNetworkId) { SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } } else { - TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1165,9 +1163,9 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - Path *const rp = nhp->getBestPath(now); - if (rp) - nextHopBestPathAddress[h] = rp->address(); + SharedPtr nhbp(nhp->getBestPath(now,false)); + if (nhbp) + nextHopBestPathAddress[h] = nhbp->address(); } } } @@ -1190,8 +1188,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint64_t)packetId()); peer->address().appendTo(outp); outp.append((uint8_t)hops()); - _localAddress.serialize(outp); - _remoteAddress.serialize(outp); + _path->localAddress().serialize(outp); + _path->address().serialize(outp); outp.append((uint16_t)0); // no additional fields outp.append((uint8_t)breadth); for(unsigned int h=0;hreceived(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1263,9 +1261,9 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S } RR->node->postCircuitTestReport(&report); - peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } @@ -1308,28 +1306,28 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const outp.append((uint16_t)sizeof(result)); outp.append(result,sizeof(result)); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); outp.append(pid); outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST); outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } break; default: - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_path->address().toString().c_str()); break; } - peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); } else { - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); } } catch ( ... ) { - TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } diff --git a/node/Node.cpp b/node/Node.cpp index ff564eee..39e24325 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -415,16 +415,16 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; - std::vector paths(pi->second->paths()); - Path *bestPath = pi->second->getBestPath(_now); + std::vector< SharedPtr > paths(pi->second->paths()); + SharedPtr bestp(pi->second->getBestPath(_now,true)); p->pathCount = 0; - for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { - memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].lastSend = path->lastSend(); - p->paths[p->pathCount].lastReceive = path->lastReceived(); - p->paths[p->pathCount].active = path->active(_now) ? 1 : 0; - p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0; - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->address()); + for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { + memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); + p->paths[p->pathCount].lastSend = (*path)->lastOut(); + p->paths[p->pathCount].lastReceive = (*path)->lastIn(); + p->paths[p->pathCount].active = (*path)->alive(_now) ? 1 : 0; + p->paths[p->pathCount].preferred = (*path == bestp) ? 1 : 0; + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); ++p->pathCount; } } diff --git a/node/Path.hpp b/node/Path.hpp index f8d84d4b..68a630c3 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -105,8 +105,7 @@ public: _lastIn(0), _addr(), _localAddress(), - _ipScope(InetAddress::IP_SCOPE_NONE), - _clusterSuboptimal(false) + _ipScope(InetAddress::IP_SCOPE_NONE) { } @@ -115,27 +114,10 @@ public: _lastIn(0), _addr(addr), _localAddress(localAddress), - _ipScope(addr.ipScope()), - _clusterSuboptimal(false) + _ipScope(addr.ipScope()) { } - inline Path &operator=(const Path &p) - { - if (this != &p) - memcpy(this,&p,sizeof(Path)); - return *this; - } - - /** - * Called when a packet is sent to this remote path - * - * This is called automatically by Path::send(). - * - * @param t Time of send - */ - inline void sent(const uint64_t t) { _lastOut = t; } - /** * Called when a packet is received from this remote path, regardless of content * @@ -157,37 +139,22 @@ public: /** * @return Address of local side of this path or NULL if unspecified */ - inline const InetAddress &localAddress() const throw() { return _localAddress; } + inline const InetAddress &localAddress() const { return _localAddress; } /** * @return Physical address */ - inline const InetAddress &address() const throw() { return _addr; } + inline const InetAddress &address() const { return _addr; } /** * @return IP scope -- faster shortcut for address().ipScope() */ - inline InetAddress::IpScope ipScope() const throw() { return _ipScope; } - - /** - * @param f Is this path cluster-suboptimal? - */ - inline void setClusterSuboptimal(const bool f) { _clusterSuboptimal = f; } - - /** - * @return True if cluster-suboptimal (for someone) - */ - inline bool isClusterSuboptimal() const { return _clusterSuboptimal; } - - /** - * @return True if cluster-optimal (for someone) (the default) - */ - inline bool isClusterOptimal() const { return (!(_clusterSuboptimal)); } + inline InetAddress::IpScope ipScope() const { return _ipScope; } /** * @return Preference rank, higher == better (will be less than 255) */ - inline unsigned int preferenceRank() const throw() + inline unsigned int preferenceRank() const { /* First, since the scope enum values in InetAddress.hpp are in order of * use preference rank, we take that. Then we multiple by two, yielding @@ -201,20 +168,9 @@ public: /** * @return This path's overall quality score (higher is better) */ - inline uint64_t score() const throw() + inline uint64_t score() const { - // This is a little bit convoluted because we try to be branch-free, using multiplication instead of branches for boolean flags - - // Start with the last time this path was active, and add a fudge factor to prevent integer underflow if _lastReceived is 0 - uint64_t score = _lastIn + (ZT_PEER_DIRECT_PING_DELAY * (ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION + 1)); - - // Increase score based on path preference rank, which is based on IP scope and address family - score += preferenceRank() * (ZT_PEER_DIRECT_PING_DELAY / ZT_PATH_MAX_PREFERENCE_RANK); - - // Decrease score if this is known to be a sub-optimal path to a cluster - score -= ((uint64_t)_clusterSuboptimal) * ZT_PEER_DIRECT_PING_DELAY; - - return score; + return (_lastIn + (preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))); } /** @@ -227,7 +183,6 @@ public: * @return True if address is good for ZeroTier path use */ static inline bool isAddressValidForPath(const InetAddress &a) - throw() { if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) { switch(a.ipScope()) { @@ -258,6 +213,26 @@ public: return false; } + /** + * @return True if path appears alive + */ + inline bool alive(const uint64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } + + /** + * @return True if this path needs a heartbeat + */ + inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) > ZT_PATH_HEARTBEAT_PERIOD); } + + /** + * @return Last time we sent something + */ + inline uint64_t lastOut() const { return _lastOut; } + + /** + * @return Last time we received anything + */ + inline uint64_t lastIn() const { return _lastIn; } + private: uint64_t _lastOut; uint64_t _lastIn; @@ -265,7 +240,6 @@ private: InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often AtomicCounter __refCount; - bool _clusterSuboptimal; }; } // namespace ZeroTier diff --git a/node/Peer.cpp b/node/Peer.cpp index 01492be1..251c5a5f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,8 +27,6 @@ #include "Cluster.hpp" #include "Packet.hpp" -#include - #define ZT_PEER_PATH_SORT_INTERVAL 5000 namespace ZeroTier { @@ -45,7 +43,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastAnnouncedTo(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), - _lastPathSort(0), _vProto(0), _vMajor(0), _vMinor(0), @@ -60,8 +57,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident } void Peer::received( - const InetAddress &localAddr, - const InetAddress &remoteAddr, + const SharedPtr &path, unsigned int hops, uint64_t packetId, Packet::Verb verb, @@ -69,13 +65,15 @@ void Peer::received( Packet::Verb inReVerb, const bool trustEstablished) { + const uint64_t now = RR->node->now(); + #ifdef ZT_ENABLE_CLUSTER bool suboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { // Note: findBetterEndpoint() is first since we still want to check // for a better endpoint even if we don't actually send a redirect. InetAddress redirectTo; - if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),remoteAddr,false)) ) { + if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),path->address(),false)) ) { if (_vProto >= 5) { // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS. Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); @@ -93,7 +91,7 @@ void Peer::received( } outp.append((uint16_t)redirectTo.port()); outp.armor(_key,true); - RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); + path->send(RR,outp.data(),outp.size(),now); } else { // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -108,14 +106,13 @@ void Peer::received( outp.append(redirectTo.rawIpData(),16); } outp.armor(_key,true); - RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); + path->send(RR,outp.data(),outp.size(),now); } suboptimalPath = true; } } #endif - const uint64_t now = RR->node->now(); _lastReceive = now; if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME)) _lastUnicastFrame = now; @@ -124,53 +121,47 @@ void Peer::received( if (hops == 0) { bool pathIsConfirmed = false; - unsigned int np = _numPaths; - for(unsigned int p=0;pnode->shouldUsePathForZeroTierTraffic(localAddr,remoteAddr))) { + if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address()))) { if (verb == Packet::VERB_OK) { + Mutex::Lock _l(_paths_m); - Path *slot = (Path *)0; - if (np < ZT_MAX_PEER_NETWORK_PATHS) { - slot = &(_paths[np++]); + unsigned int slot = 0; + if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { + slot = _numPaths++; } else { - uint64_t slotWorstScore = 0xffffffffffffffffULL; - for(unsigned int p=0;preceived(now); -#ifdef ZT_ENABLE_CLUSTER - slot->setClusterSuboptimal(suboptimalPath); -#endif - _numPaths = np; + slot = oldestPath; } + _paths[slot].path = path; + _paths[slot].lastReceive = now; #ifdef ZT_ENABLE_CLUSTER + _paths[slot].clusterSuboptimal = suboptimalPath; + if (RR->cluster) RR->cluster->broadcastHavePeer(_id); #endif - } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str()); @@ -178,15 +169,15 @@ void Peer::received( if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); outp.armor(_key,true); - RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); + path->send(RR,outp.data(),outp.size(),now); } else { - sendHELLO(localAddr,remoteAddr,now); + sendHELLO(path->localAddress(),path->address(),now); } } } } else if (trustEstablished) { - _pushDirectPaths(localAddr,remoteAddr,now); + _pushDirectPaths(path,now); } if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { @@ -197,7 +188,96 @@ void Peer::received( } } -void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl) +bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const +{ + Mutex::Lock _l(_paths_m); + for(unsigned int p=0;p<_numPaths;++p) { + if ( (_paths[p].path->address() == addr) && (_paths[p].path->alive(now)) ) + return true; + } + return false; +} + +void Peer::makeExclusive(const InetAddress &addr) +{ + Mutex::Lock _l(_paths_m); + + bool have = false; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->address() == addr) { + have = true; + break; + } + } + + if (have) { + unsigned int np = _numPaths; + unsigned int x = 0; + unsigned int y = 0; + while (x < np) { + if ((_paths[x].path->address().ss_family != addr.ss_family)||(_paths[x].path->address() == addr)) { + if (y != x) { + _paths[y].path = _paths[x].path; + _paths[y].lastReceive = _paths[x].lastReceive; + #ifdef ZT_ENABLE_CLUSTER + _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; + #endif + } + ++y; + } + ++x; + } + _numPaths = y; + } +} + +bool Peer::send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +{ + Mutex::Lock _l(_paths_m); + + int bestp = -1; + uint64_t best = 0ULL; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->alive(now)||(forceEvenIfDead)) { + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; + } + } + } + + if (bestp >= 0) { + return _paths[bestp].path->send(RR,data,len,now); + } else { + return false; + } +} + +SharedPtr Peer::getBestPath(uint64_t now,bool forceEvenIfDead) +{ + Mutex::Lock _l(_paths_m); + + int bestp = -1; + uint64_t best = 0ULL; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->alive(now)||(forceEvenIfDead)) { + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; + } + } + } + + if (bestp >= 0) { + return _paths[bestp].path; + } else { + return SharedPtr(); + } +} + +void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); outp.append((unsigned char)ZT_PROTO_VERSION); @@ -209,51 +289,56 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u atAddress.serialize(outp); outp.append((uint64_t)RR->topology->worldId()); outp.append((uint64_t)RR->topology->worldTimestamp()); - outp.armor(_key,false); // HELLO is sent in the clear - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size(),ttl); + RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { - Path *p = (Path *)0; - - if (inetAddressFamily != 0) { - p = _getBestPath(now,inetAddressFamily); - } else { - p = _getBestPath(now); - } - - if (p) { - if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { - //TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); - sendHELLO(p->localAddress(),p->address(),now); - p->sent(now); - p->pinged(now); - } else if ((now - std::max(p->lastSend(),p->lastKeepalive())) >= ZT_NAT_KEEPALIVE_DELAY) { - //TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived()); + bool somethingAlive = false; + Mutex::Lock _l(_paths_m); + for(unsigned int p=0;p<_numPaths;++p) { + if ((now - _paths[p].lastReceive) >= ZT_PEER_PING_PERIOD) { + sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); + } else if (_paths[p].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); - p->sentKeepalive(now); + _paths[p].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); } - return true; + somethingAlive |= _paths[p].path->alive(now); } + return somethingAlive; +} +bool Peer::hasActiveDirectPath(uint64_t now) const +{ + Mutex::Lock _l(_paths_m); + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->alive(now)) + return true; + } return false; } bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) { + Mutex::Lock _l(_paths_m); unsigned int np = _numPaths; unsigned int x = 0; unsigned int y = 0; while (x < np) { - if (_paths[x].address().ipScope() == scope) { + if (_paths[x].path->address().ipScope() == scope) { // Resetting a path means sending a HELLO and then forgetting it. If we // get OK(HELLO) then it will be re-learned. - sendHELLO(_paths[x].localAddress(),_paths[x].address(),now); + sendHELLO(_paths[x].path->localAddress(),_paths[x].path->address(),now); } else { - _paths[y++] = _paths[x]; + if (x != y) { + _paths[y].path = _paths[x].path; + _paths[y].lastReceive = _paths[x].lastReceive; +#ifdef ZT_ENABLE_CLUSTER + _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; +#endif + } + ++y; } ++x; } @@ -263,114 +348,55 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const { - uint64_t bestV4 = 0,bestV6 = 0; - for(unsigned int p=0,np=_numPaths;p= bestV4) { - bestV4 = lr; - v4 = _paths[p].address(); - } - } else if (_paths[p].address().isV6()) { - if (lr >= bestV6) { - bestV6 = lr; - v6 = _paths[p].address(); - } - } + Mutex::Lock _l(_paths_m); + + int bestp4 = -1,bestp6 = -1; + uint64_t best4 = 0ULL,best6 = 0ULL; + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->address().ss_family == AF_INET) { + const uint64_t s = _paths[p].path->score(); + if (s >= best4) { + best4 = s; + bestp4 = (int)p; + } + } else if (_paths[p].path->address().ss_family == AF_INET6) { + const uint64_t s = _paths[p].path->score(); + if (s >= best6) { + best6 = s; + bestp6 = (int)p; } } } + + if (bestp4 >= 0) + v4 = _paths[bestp4].path->address(); + if (bestp6 >= 0) + v6 = _paths[bestp6].path->address(); } void Peer::clean(uint64_t now) { + Mutex::Lock _l(_paths_m); unsigned int np = _numPaths; unsigned int x = 0; unsigned int y = 0; while (x < np) { - if (_paths[x].active(now)) - _paths[y++] = _paths[x]; + if ((now - _paths[x].lastReceive) <= ZT_PEER_PATH_EXPIRATION) { + if (y != x) { + _paths[y].path = _paths[x].path; + _paths[y].lastReceive = _paths[x].lastReceive; +#ifdef ZT_ENABLE_CLUSTER + _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; +#endif + } + ++y; + } ++x; } _numPaths = y; } -void Peer::_doDeadPathDetection(Path &p,const uint64_t now) -{ - /* Dead path detection: if we have sent something to this peer and have not - * yet received a reply, double check this path. The majority of outbound - * packets including Ethernet frames do generate some kind of reply either - * immediately or at some point in the near future. This will occasionally - * (every NO_ANSWER_TIMEOUT ms) check paths unnecessarily if traffic that - * does not generate a response is being sent such as multicast announcements - * or frames belonging to unidirectional UDP protocols, but the cost is very - * tiny and the benefit in reliability is very large. This takes care of many - * failure modes including crap NATs that forget links and spurious changes - * to physical network topology that cannot be otherwise detected. - * - * Each time we do this we increment a probation counter in the path. This - * counter is reset on any packet receive over this path. If it reaches the - * MAX_PROBATION threshold the path is considred dead. */ - - if ( - (p.lastSend() > p.lastReceived()) && - ((p.lastSend() - p.lastReceived()) >= ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT) && - ((now - p.lastPing()) >= ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT) && - (!p.isClusterSuboptimal()) && - (!RR->topology->amRoot()) - ) { - TRACE("%s(%s) does not seem to be answering in a timely manner, checking if dead (probation == %u)",_id.address().toString().c_str(),p.address().toString().c_str(),p.probation()); - - if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); - outp.armor(_key,true); - p.send(RR,outp.data(),outp.size(),now); - p.pinged(now); - } else { - sendHELLO(p.localAddress(),p.address(),now); - p.sent(now); - p.pinged(now); - } - - p.increaseProbation(); - } -} - -Path *Peer::_getBestPath(const uint64_t now) -{ - Path *bestPath = (Path *)0; - uint64_t bestPathScore = 0; - for(unsigned int i=0;i<_numPaths;++i) { - const uint64_t score = _paths[i].score(); - if ((score >= bestPathScore)&&(_paths[i].active(now))) { - bestPathScore = score; - bestPath = &(_paths[i]); - } - } - if (bestPath) - _doDeadPathDetection(*bestPath,now); - return bestPath; -} - -Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily) -{ - Path *bestPath = (Path *)0; - uint64_t bestPathScore = 0; - for(unsigned int i=0;i<_numPaths;++i) { - const uint64_t score = _paths[i].score(); - if (((int)_paths[i].address().ss_family == inetAddressFamily)&&(score >= bestPathScore)&&(_paths[i].active(now))) { - bestPathScore = score; - bestPath = &(_paths[i]); - } - } - if (bestPath) - _doDeadPathDetection(*bestPath,now); - return bestPath; -} - -bool Peer::_pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now) +bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) { #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection @@ -445,7 +471,7 @@ bool Peer::_pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAd if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); outp.armor(_key,true); - RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0); + path->send(RR,outp.data(),outp.size(),now); } } diff --git a/node/Peer.hpp b/node/Peer.hpp index a6940737..ff32184f 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -96,9 +96,7 @@ public: * This is called by the decode pipe when a packet is proven to be authentic * and appears to be valid. * - * @param RR Runtime environment - * @param localAddr Local address - * @param remoteAddr Internet address of sender + * @param path Path over which packet was received * @param hops ZeroTier (not IP) hops * @param packetId Packet ID * @param verb Packet verb @@ -107,8 +105,7 @@ public: * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established */ void received( - const InetAddress &localAddr, - const InetAddress &remoteAddr, + const SharedPtr &path, unsigned int hops, uint64_t packetId, Packet::Verb verb, @@ -116,43 +113,19 @@ public: Packet::Verb inReVerb, const bool trustEstablished); - /** - * Get the current best direct path to this peer - * - * @param now Current time - * @return Best path or NULL if there are no active direct paths - */ - inline Path *getBestPath(uint64_t now) { return _getBestPath(now); } - /** * @param now Current time * @param addr Remote address * @return True if we have an active path to this destination */ - inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const - { - for(unsigned int p=0;p<_numPaths;++p) { - if ((_paths[p].active(now))&&(_paths[p].address() == addr)) - return true; - } - return false; - } + bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; /** - * Set all paths in the same ss_family that are not this one to cluster suboptimal - * - * Addresses in other families are not affected. + * If we have a confirmed path to this address, forget all others within the same address family * * @param addr Address to make exclusive */ - inline void setClusterOptimalPathForAddressFamily(const InetAddress &addr) - { - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].address().ss_family == addr.ss_family) { - _paths[p].setClusterSuboptimal(_paths[p].address() != addr); - } - } - } + void makeExclusive(const InetAddress &addr); /** * Send via best path @@ -160,30 +133,30 @@ public: * @param data Packet data * @param len Packet length * @param now Current time - * @return Path used on success or NULL on failure + * @param forceEvenIfDead If true, send even if the path is not 'alive' + * @return True if we actually sent something */ - inline Path *send(const void *data,unsigned int len,uint64_t now) - { - Path *const bestPath = getBestPath(now); - if (bestPath) { - if (bestPath->send(RR,data,len,now)) - return bestPath; - } - return (Path *)0; - } + bool send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + + /** + * Get the best current direct path + * + * @param now Current time + * @param forceEvenIfDead If true, pick even if path is not alive + * @return Best current path or NULL if none + */ + SharedPtr getBestPath(uint64_t now,bool forceEvenIfDead); /** * Send a HELLO to this peer at a specified physical address * - * This does not update any statistics. It's used to send initial HELLOs - * for NAT traversal and path verification. + * No statistics or sent times are updated here. * * @param localAddr Local address * @param atAddress Destination address * @param now Current time - * @param ttl Desired IP TTL (default: 0 to leave alone) */ - void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl = 0); + void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); /** * Send pings or keepalives depending on configured timeouts @@ -194,14 +167,49 @@ public: */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); + /** + * @param now Current time + * @return True if this peer has at least one active direct path + */ + bool hasActiveDirectPath(uint64_t now) const; + + /** + * Reset paths within a given scope + * + * @param scope IP scope of paths to reset + * @param now Current time + * @return True if at least one path was forgotten + */ + bool resetWithinScope(InetAddress::IpScope scope,uint64_t now); + + /** + * Get most recently active path addresses for IPv4 and/or IPv6 + * + * Note that v4 and v6 are not modified if they are not found, so + * initialize these to a NULL address to be able to check. + * + * @param now Current time + * @param v4 Result parameter to receive active IPv4 address, if any + * @param v6 Result parameter to receive active IPv6 address, if any + */ + void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + + /** + * Perform periodic cleaning operations + * + * @param now Current time + */ + void clean(uint64_t now); + /** * @return All known direct paths to this peer (active or inactive) */ - inline std::vector paths() const + inline std::vector< SharedPtr > paths() const { - std::vector pp; + std::vector< SharedPtr > pp; + Mutex::Lock _l(_paths_m); for(unsigned int p=0,np=_numPaths;palive(now)) && (!_paths[p].clusterSuboptimal) ) return true; } return false; } #endif - /** - * Reset paths within a given scope - * - * @param scope IP scope of paths to reset - * @param now Current time - * @return True if at least one path was forgotten - */ - bool resetWithinScope(InetAddress::IpScope scope,uint64_t now); - /** * @return 256-bit secret symmetric encryption key */ @@ -335,25 +321,6 @@ public: inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } - /** - * Get most recently active path addresses for IPv4 and/or IPv6 - * - * Note that v4 and v6 are not modified if they are not found, so - * initialize these to a NULL address to be able to check. - * - * @param now Current time - * @param v4 Result parameter to receive active IPv4 address, if any - * @param v6 Result parameter to receive active IPv6 address, if any - */ - void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; - - /** - * Perform periodic cleaning operations - * - * @param now Current time - */ - void clean(uint64_t now); - /** * Update direct path push stats and return true if we should respond * @@ -395,10 +362,7 @@ public: } private: - void _doDeadPathDetection(Path &p,const uint64_t now); - Path *_getBestPath(const uint64_t now); - Path *_getBestPath(const uint64_t now,int inetAddressFamily); - bool _pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now); + bool _pushDirectPaths(const SharedPtr &path,uint64_t now); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -410,13 +374,19 @@ private: uint64_t _lastAnnouncedTo; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; - uint64_t _lastPathSort; uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; Identity _id; - Path _paths[ZT_MAX_PEER_NETWORK_PATHS]; + struct { + SharedPtr path; + uint64_t lastReceive; +#ifdef ZT_ENABLE_CLUSTER + bool clusterSuboptimal; +#endif + } _paths[ZT_MAX_PEER_NETWORK_PATHS]; + Mutex _paths_m; unsigned int _numPaths; unsigned int _latency; unsigned int _directPathPushCutoffCount; diff --git a/node/Switch.cpp b/node/Switch.cpp index dc238607..ab07d353 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -112,7 +112,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now))) { + if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now,true))) { #ifdef ZT_ENABLE_CLUSTER if (RR->cluster) { RR->cluster->sendViaCluster(Address(),destination,fragment.data(),fragment.size(),false); @@ -123,7 +123,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Don't know peer or no direct path -- so relay via root server relayTo = RR->topology->getBestRoot(); if (relayTo) - relayTo->send(fragment.data(),fragment.size(),now); + relayTo->send(fragment.data(),fragment.size(),now,true); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -210,7 +210,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from packet.incrementHops(); SharedPtr relayTo = RR->topology->getPeer(destination); - if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now)))) { + if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now,true)))) { Mutex::Lock _l(_lastUniteAttempt_m); uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)]; if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) { @@ -234,7 +234,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from #endif relayTo = RR->topology->getBestRoot(&source,1,true); if (relayTo) - relayTo->send(packet.data(),packet.size(),now); + relayTo->send(packet.data(),packet.size(),now,true); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -251,7 +251,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from rq->timestamp = now; rq->packetId = packetId; - rq->frag0.init(data,len,localAddr,fromAddr,now); + rq->frag0.init(data,len,path,now); rq->totalFragments = 0; rq->haveFragments = 1; rq->complete = false; @@ -607,7 +607,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.first.rawIpData(),4); } outp.armor(p1p->key(),true); - p1p->send(outp.data(),outp.size(),now); + p1p->send(outp.data(),outp.size(),now,true); } else { // Tell p2 where to find p1. Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -622,7 +622,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.second.rawIpData(),4); } outp.armor(p2p->key(),true); - p2p->send(outp.data(),outp.size(),now); + p2p->send(outp.data(),outp.size(),now,true); } ++alt; // counts up and also flips LSB } @@ -739,7 +739,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); outp.armor(root->key(),true); - if (root->send(outp.data(),outp.size(),RR->node->now())) + if (root->send(outp.data(),outp.size(),RR->node->now(),true)) return root->address(); } return Address(); @@ -752,12 +752,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) if (peer) { const uint64_t now = RR->node->now(); - Path *viaPath = peer->getBestPath(now); - SharedPtr relay; - + SharedPtr viaPath(peer->getBestPath(now,false)); if (!viaPath) { - relay = RR->topology->getBestRoot(); - if ( (!relay) || (!(viaPath = relay->getBestPath(now))) ) + SharedPtr relay(RR->topology->getBestRoot()); + if ( (!relay) || (!(viaPath = relay->getBestPath(now,true))) ) return false; } -- cgit v1.2.3 From d1101441b3d43ee69c1b661cc5f777a09fd10fca Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 11:54:59 -0700 Subject: Tweak some timings. --- node/Constants.hpp | 6 +++--- node/Peer.cpp | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 6d6f44e0..b783e2c2 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -244,17 +244,17 @@ * This is also how often pings will be retried to upstream peers (relays, roots) * constantly until something is heard. */ -#define ZT_PING_CHECK_INVERVAL 8000 +#define ZT_PING_CHECK_INVERVAL 9000 /** * How frequently to send heartbeats over in-use paths */ -#define ZT_PATH_HEARTBEAT_PERIOD 18000 +#define ZT_PATH_HEARTBEAT_PERIOD 15000 /** * Paths are considered inactive if they have not received traffic in this long */ -#define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_HEARTBEAT_PERIOD * 2) + 2000) +#define ZT_PATH_ALIVE_TIMEOUT 35000 /** * Delay between full-fledge pings of directly connected peers diff --git a/node/Peer.cpp b/node/Peer.cpp index 251c5a5f..9b5d84fc 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,8 +27,6 @@ #include "Cluster.hpp" #include "Packet.hpp" -#define ZT_PEER_PATH_SORT_INTERVAL 5000 - namespace ZeroTier { // Used to send varying values for NAT keepalive -- cgit v1.2.3 From 4f8253dcdb9e6ff2ae18639556811d13729fae2b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 13:33:56 -0700 Subject: Tweaks to path handling... --- node/IncomingPacket.cpp | 4 ++-- node/Node.cpp | 2 +- node/Peer.cpp | 39 ++++++++++++++++++++++++--------------- node/Peer.hpp | 7 +++---- node/Switch.cpp | 21 +++++++++++---------- 5 files changed, 41 insertions(+), 32 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index fafd5679..7ba34566 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1163,8 +1163,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - SharedPtr nhbp(nhp->getBestPath(now,false)); - if (nhbp) + SharedPtr nhbp(nhp->getBestPath(now)); + if ((nhbp)&&(nhbp->alive(now))) nextHopBestPathAddress[h] = nhbp->address(); } } diff --git a/node/Node.cpp b/node/Node.cpp index 39e24325..d2840bd0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -416,7 +416,7 @@ ZT_PeerList *Node::peers() const p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; std::vector< SharedPtr > paths(pi->second->paths()); - SharedPtr bestp(pi->second->getBestPath(_now,true)); + SharedPtr bestp(pi->second->getBestPath(_now)); p->pathCount = 0; for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); diff --git a/node/Peer.cpp b/node/Peer.cpp index 9b5d84fc..a23d0822 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -229,7 +229,7 @@ void Peer::makeExclusive(const InetAddress &addr) } } -bool Peer::send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) { Mutex::Lock _l(_paths_m); @@ -252,19 +252,17 @@ bool Peer::send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfD } } -SharedPtr Peer::getBestPath(uint64_t now,bool forceEvenIfDead) +SharedPtr Peer::getBestPath(uint64_t now) { Mutex::Lock _l(_paths_m); int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->alive(now)||(forceEvenIfDead)) { - const uint64_t s = _paths[p].path->score(); - if (s >= best) { - best = s; - bestp = (int)p; - } + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; } } @@ -293,18 +291,29 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { - bool somethingAlive = false; Mutex::Lock _l(_paths_m); + + int bestp = -1; + uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ((now - _paths[p].lastReceive) >= ZT_PEER_PING_PERIOD) { - sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); - } else if (_paths[p].path->needsHeartbeat(now)) { + const uint64_t s = _paths[p].path->score(); + if (s >= best) { + best = s; + bestp = (int)p; + } + } + + if (bestp >= 0) { + if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { + sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - _paths[p].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); + _paths[bestp].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); } - somethingAlive |= _paths[p].path->alive(now); + return true; + } else { + return false; } - return somethingAlive; } bool Peer::hasActiveDirectPath(uint64_t now) const diff --git a/node/Peer.hpp b/node/Peer.hpp index ff32184f..87aea486 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -128,7 +128,7 @@ public: void makeExclusive(const InetAddress &addr); /** - * Send via best path + * Send via best direct path * * @param data Packet data * @param len Packet length @@ -136,16 +136,15 @@ public: * @param forceEvenIfDead If true, send even if the path is not 'alive' * @return True if we actually sent something */ - bool send(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); /** * Get the best current direct path * * @param now Current time - * @param forceEvenIfDead If true, pick even if path is not alive * @return Best current path or NULL if none */ - SharedPtr getBestPath(uint64_t now,bool forceEvenIfDead); + SharedPtr getBestPath(uint64_t now); /** * Send a HELLO to this peer at a specified physical address diff --git a/node/Switch.cpp b/node/Switch.cpp index ab07d353..125c4b69 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -75,6 +75,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from SharedPtr path(RR->topology->getPath(localAddr,fromAddr)); path->received(now); + printf("<< %s %u\n",fromAddr.toString().c_str(),len); if (len == 13) { /* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast @@ -112,7 +113,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now,true))) { + if ((!relayTo)||(!relayTo->sendDirect(fragment.data(),fragment.size(),now,false))) { #ifdef ZT_ENABLE_CLUSTER if (RR->cluster) { RR->cluster->sendViaCluster(Address(),destination,fragment.data(),fragment.size(),false); @@ -123,7 +124,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Don't know peer or no direct path -- so relay via root server relayTo = RR->topology->getBestRoot(); if (relayTo) - relayTo->send(fragment.data(),fragment.size(),now,true); + relayTo->sendDirect(fragment.data(),fragment.size(),now,true); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -210,7 +211,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from packet.incrementHops(); SharedPtr relayTo = RR->topology->getPeer(destination); - if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now,true)))) { + if ((relayTo)&&((relayTo->sendDirect(packet.data(),packet.size(),now,false)))) { Mutex::Lock _l(_lastUniteAttempt_m); uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)]; if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) { @@ -234,7 +235,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from #endif relayTo = RR->topology->getBestRoot(&source,1,true); if (relayTo) - relayTo->send(packet.data(),packet.size(),now,true); + relayTo->sendDirect(packet.data(),packet.size(),now,true); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -607,7 +608,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.first.rawIpData(),4); } outp.armor(p1p->key(),true); - p1p->send(outp.data(),outp.size(),now,true); + p1p->sendDirect(outp.data(),outp.size(),now,true); } else { // Tell p2 where to find p1. Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -622,7 +623,7 @@ bool Switch::unite(const Address &p1,const Address &p2) outp.append(cg.second.rawIpData(),4); } outp.armor(p2p->key(),true); - p2p->send(outp.data(),outp.size(),now,true); + p2p->sendDirect(outp.data(),outp.size(),now,true); } ++alt; // counts up and also flips LSB } @@ -739,7 +740,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); outp.armor(root->key(),true); - if (root->send(outp.data(),outp.size(),RR->node->now(),true)) + if (root->sendDirect(outp.data(),outp.size(),RR->node->now(),true)) return root->address(); } return Address(); @@ -752,10 +753,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) if (peer) { const uint64_t now = RR->node->now(); - SharedPtr viaPath(peer->getBestPath(now,false)); - if (!viaPath) { + SharedPtr viaPath(peer->getBestPath(now)); + if ( (!viaPath) || ((!viaPath->alive(now))&&(!RR->topology->isRoot(peer->identity()))) ) { SharedPtr relay(RR->topology->getBestRoot()); - if ( (!relay) || (!(viaPath = relay->getBestPath(now,true))) ) + if ( (!relay) || (!(viaPath = relay->getBestPath(now))) ) return false; } -- cgit v1.2.3 From 4992ac2d9f568a08ecd04b316a926c9d320750df Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 2 Sep 2016 14:20:55 -0700 Subject: Cluster sub-optimal is in fact necessary... --- node/IncomingPacket.cpp | 4 ++-- node/Path.hpp | 8 -------- node/Peer.cpp | 40 +++++++++++++--------------------------- node/Peer.hpp | 11 +++++++---- 4 files changed, 22 insertions(+), 41 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7ba34566..a84b2beb 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1042,7 +1042,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->makeExclusive(a); + peer->setClusterOptimal(a); } else { redundant = peer->hasActivePathTo(now,a); } @@ -1061,7 +1061,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha bool redundant = false; if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->makeExclusive(a); + peer->setClusterOptimal(a); } else { redundant = peer->hasActivePathTo(now,a); } diff --git a/node/Path.hpp b/node/Path.hpp index 68a630c3..d0e1d737 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -165,14 +165,6 @@ public: return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); } - /** - * @return This path's overall quality score (higher is better) - */ - inline uint64_t score() const - { - return (_lastIn + (preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))); - } - /** * Check whether this address is valid for a ZeroTier path * diff --git a/node/Peer.cpp b/node/Peer.cpp index a23d0822..ecf2a870 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -156,9 +156,10 @@ void Peer::received( _paths[slot].lastReceive = now; #ifdef ZT_ENABLE_CLUSTER _paths[slot].clusterSuboptimal = suboptimalPath; - if (RR->cluster) RR->cluster->broadcastHavePeer(_id); +#else + _paths[slot].clusterSuboptimal = false; #endif } else { @@ -196,36 +197,21 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const return false; } -void Peer::makeExclusive(const InetAddress &addr) +void Peer::setClusterOptimal(const InetAddress &addr) { Mutex::Lock _l(_paths_m); - bool have = false; + int have = -1; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address() == addr) { - have = true; + have = (int)p; break; } } - if (have) { - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if ((_paths[x].path->address().ss_family != addr.ss_family)||(_paths[x].path->address() == addr)) { - if (y != x) { - _paths[y].path = _paths[x].path; - _paths[y].lastReceive = _paths[x].lastReceive; - #ifdef ZT_ENABLE_CLUSTER - _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; - #endif - } - ++y; - } - ++x; - } - _numPaths = y; + if (have >= 0) { + for(unsigned int p=0;p<_numPaths;++p) + _paths[p].clusterSuboptimal = (p != have); } } @@ -237,7 +223,7 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->alive(now)||(forceEvenIfDead)) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best) { best = s; bestp = (int)p; @@ -259,7 +245,7 @@ SharedPtr Peer::getBestPath(uint64_t now) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best) { best = s; bestp = (int)p; @@ -296,7 +282,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best) { best = s; bestp = (int)p; @@ -361,13 +347,13 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) uint64_t best4 = 0ULL,best6 = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best4) { best4 = s; bestp4 = (int)p; } } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _paths[p].path->score(); + const uint64_t s = _pathScore(p); if (s >= best6) { best6 = s; bestp6 = (int)p; diff --git a/node/Peer.hpp b/node/Peer.hpp index 294a4913..efe34825 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -121,11 +121,11 @@ public: bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; /** - * If we have a confirmed path to this address, forget all others within the same address family + * If we have a confirmed path to this address, mark others as cluster suboptimal * * @param addr Address to make exclusive */ - void makeExclusive(const InetAddress &addr); + void setClusterOptimal(const InetAddress &addr); /** * Send via best direct path @@ -363,6 +363,11 @@ public: private: bool _pushDirectPaths(const SharedPtr &path,uint64_t now); + inline uint64_t _pathScore(const unsigned int p) const + { + return ( (_paths[p].path->lastIn() + (_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))) - ((ZT_PEER_PING_PERIOD * 10) * (uint64_t)_paths[p].clusterSuboptimal) ); + } + unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; const RuntimeEnvironment *RR; @@ -381,9 +386,7 @@ private: struct { SharedPtr path; uint64_t lastReceive; -#ifdef ZT_ENABLE_CLUSTER bool clusterSuboptimal; -#endif } _paths[ZT_MAX_PEER_NETWORK_PATHS]; Mutex _paths_m; unsigned int _numPaths; -- cgit v1.2.3 From eebcf08084097fc7cd8703a11686e66157fa8efa Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sat, 3 Sep 2016 15:39:05 -0700 Subject: Tweaks to new Path code for dual-stack operation, and other fixes. --- include/ZeroTierOne.h | 5 ----- node/Constants.hpp | 2 +- node/Network.cpp | 2 +- node/Node.cpp | 3 +-- node/Peer.cpp | 58 +++++++++++++++++++++++++----------------------- node/Peer.hpp | 16 ++++++++----- one.cpp | 10 ++++----- service/ControlPlane.cpp | 4 ++-- 8 files changed, 50 insertions(+), 50 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index db0560a3..583abfe4 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1053,11 +1053,6 @@ typedef struct */ uint64_t trustedPathId; - /** - * Is path active? - */ - int active; - /** * Is path preferred? */ diff --git a/node/Constants.hpp b/node/Constants.hpp index b783e2c2..ea4c434d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -264,7 +264,7 @@ /** * Peers forget paths that have not spoken in this long */ -#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 3) + 3000) +#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) /** * Timeout for overall peer activity (measured from last receive) diff --git a/node/Network.cpp b/node/Network.cpp index 4dc8aa30..b18a3b22 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -36,7 +36,7 @@ #include "Peer.hpp" // Uncomment to make the rules engine dump trace info to stdout -#define ZT_RULES_ENGINE_DEBUGGING 1 +//#define ZT_RULES_ENGINE_DEBUGGING 1 namespace ZeroTier { diff --git a/node/Node.cpp b/node/Node.cpp index d2840bd0..a7d4cfa9 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -243,7 +243,7 @@ public: lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } else if (p->activelyTransferringFrames(_now)) { // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently - p->doPingAndKeepalive(_now,0); + p->doPingAndKeepalive(_now,-1); } } @@ -422,7 +422,6 @@ ZT_PeerList *Node::peers() const memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); p->paths[p->pathCount].lastSend = (*path)->lastOut(); p->paths[p->pathCount].lastReceive = (*path)->lastIn(); - p->paths[p->pathCount].active = (*path)->alive(_now) ? 1 : 0; p->paths[p->pathCount].preferred = (*path == bestp) ? 1 : 0; p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); ++p->pathCount; diff --git a/node/Peer.cpp b/node/Peer.cpp index ecf2a870..0cb55fd8 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -122,10 +122,11 @@ void Peer::received( { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path == path) { // paths are canonicalized so pointer compare is good here + if (_paths[p].path->address() == path->address()) { _paths[p].lastReceive = now; + _paths[p].path = path; // local address may have changed! #ifdef ZT_ENABLE_CLUSTER - _paths[p].clusterSuboptimal = suboptimalPath; + _paths[p].clusterWeights = (unsigned int)(!suboptimalPath); #endif pathIsConfirmed = true; break; @@ -141,25 +142,26 @@ void Peer::received( if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { slot = _numPaths++; } else { - uint64_t oldest = 0ULL; - unsigned int oldestPath = 0; + uint64_t worstScore = 0xffffffffffffffffULL; + unsigned int worstPath = ZT_MAX_PEER_NETWORK_PATHS-1; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].lastReceive < oldest) { - oldest = _paths[p].lastReceive; - oldestPath = p; + const uint64_t s = _pathScore(p); + if (s < worstScore) { + worstScore = s; + worstPath = p; } } - slot = oldestPath; + slot = worstPath; } - _paths[slot].path = path; _paths[slot].lastReceive = now; + _paths[slot].path = path; #ifdef ZT_ENABLE_CLUSTER - _paths[slot].clusterSuboptimal = suboptimalPath; + _paths[slot].clusterWeights = (unsigned int)(!suboptimalPath); if (RR->cluster) RR->cluster->broadcastHavePeer(_id); #else - _paths[slot].clusterSuboptimal = false; + _paths[slot].clusterWeights = 1; #endif } else { @@ -201,17 +203,19 @@ void Peer::setClusterOptimal(const InetAddress &addr) { Mutex::Lock _l(_paths_m); - int have = -1; + int opt = -1; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address() == addr) { - have = (int)p; + opt = (int)p; break; } } - if (have >= 0) { - for(unsigned int p=0;p<_numPaths;++p) - _paths[p].clusterSuboptimal = (p != have); + if (opt >= 0) { // only change anything if we have the optimal path + for(unsigned int p=0;p<_numPaths;++p) { + if (_paths[p].path->address().ss_family == addr.ss_family) + _paths[p].clusterWeights = ((int)p == opt) ? 2 : 0; + } } } @@ -282,10 +286,12 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); - if (s >= best) { - best = s; - bestp = (int)p; + if ((inetAddressFamily < 0)||(_paths[p].path->address().ss_family == inetAddressFamily)) { + const uint64_t s = _pathScore(p); + if (s >= best) { + best = s; + bestp = (int)p; + } } } @@ -325,11 +331,9 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) sendHELLO(_paths[x].path->localAddress(),_paths[x].path->address(),now); } else { if (x != y) { - _paths[y].path = _paths[x].path; _paths[y].lastReceive = _paths[x].lastReceive; -#ifdef ZT_ENABLE_CLUSTER - _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; -#endif + _paths[y].path = _paths[x].path; + _paths[y].clusterWeights = _paths[x].clusterWeights; } ++y; } @@ -376,11 +380,9 @@ void Peer::clean(uint64_t now) while (x < np) { if ((now - _paths[x].lastReceive) <= ZT_PEER_PATH_EXPIRATION) { if (y != x) { - _paths[y].path = _paths[x].path; _paths[y].lastReceive = _paths[x].lastReceive; -#ifdef ZT_ENABLE_CLUSTER - _paths[y].clusterSuboptimal = _paths[x].clusterSuboptimal; -#endif + _paths[y].path = _paths[x].path; + _paths[y].clusterWeights = _paths[x].clusterWeights; } ++y; } diff --git a/node/Peer.hpp b/node/Peer.hpp index efe34825..8286bfff 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -121,7 +121,9 @@ public: bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; /** - * If we have a confirmed path to this address, mark others as cluster suboptimal + * Set which known path for an address family is optimal + * + * This only modifies paths within the same address family * * @param addr Address to make exclusive */ @@ -161,7 +163,7 @@ public: * Send pings or keepalives depending on configured timeouts * * @param now Current time - * @param inetAddressFamily Keep this address family alive, or 0 to simply pick current best ignoring family + * @param inetAddressFamily Keep this address family alive, or -1 for any * @return True if we have at least one direct path */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); @@ -285,7 +287,7 @@ public: inline bool hasClusterOptimalPath(uint64_t now) const { for(unsigned int p=0,np=_numPaths;palive(now)) && (!_paths[p].clusterSuboptimal) ) + if ( (_paths[p].path->alive(now)) && ((_paths[p].clusterWeights & 1) != 0) ) return true; } return false; @@ -365,7 +367,9 @@ private: inline uint64_t _pathScore(const unsigned int p) const { - return ( (_paths[p].path->lastIn() + (_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK))) - ((ZT_PEER_PING_PERIOD * 10) * (uint64_t)_paths[p].clusterSuboptimal) ); + return ( _paths[p].path->lastIn() + + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + + (uint64_t)(_paths[p].clusterWeights * ZT_PEER_PING_PERIOD) ); } unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -384,9 +388,9 @@ private: uint16_t _vRevision; Identity _id; struct { - SharedPtr path; uint64_t lastReceive; - bool clusterSuboptimal; + SharedPtr path; + unsigned int clusterWeights; } _paths[ZT_MAX_PEER_NETWORK_PATHS]; Mutex _paths_m; unsigned int _numPaths; diff --git a/one.cpp b/one.cpp index 7cddb376..6ad5c8e6 100644 --- a/one.cpp +++ b/one.cpp @@ -330,12 +330,12 @@ static int cli(int argc,char **argv) out << "200 listpeers " << ZT_EOL_S; if (j.is_array()) { for(unsigned long k=0;k " << ZT_EOL_S; if (j.is_array()) { for(unsigned long i=0;i 0) aa.push_back(','); aa.append(addr); diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 5ed6b8b7..03c5942d 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -183,14 +183,14 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath * "%s\t\"address\": \"%s\",\n" "%s\t\"lastSend\": %llu,\n" "%s\t\"lastReceive\": %llu,\n" - "%s\t\"active\": %s,\n" + "%s\t\"active\": true,\n" "%s\t\"preferred\": %s,\n" "%s\t\"trustedPathId\": %llu\n" "%s}", prefix,_jsonEscape(reinterpret_cast(&(pp[i].address))->toString()).c_str(), prefix,pp[i].lastSend, prefix,pp[i].lastReceive, - prefix,(pp[i].active == 0) ? "false" : "true", + prefix, prefix,(pp[i].preferred == 0) ? "false" : "true", prefix,pp[i].trustedPathId, prefix); -- cgit v1.2.3 From d7f2287ce960b3a4917699e7c9c98ac26bfb8ca7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 5 Sep 2016 15:47:22 -0700 Subject: More tweaks to path behavior. --- node/Path.hpp | 10 ++-------- node/Peer.cpp | 39 +++++++++++++++++++++++++++------------ node/Peer.hpp | 4 ++-- node/Utils.cpp | 1 + service/ControlPlane.cpp | 4 ++-- 5 files changed, 34 insertions(+), 24 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Path.hpp b/node/Path.hpp index d0e1d737..718e1cdd 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -152,16 +152,10 @@ public: inline InetAddress::IpScope ipScope() const { return _ipScope; } /** - * @return Preference rank, higher == better (will be less than 255) + * @return Preference rank, higher == better */ inline unsigned int preferenceRank() const { - /* First, since the scope enum values in InetAddress.hpp are in order of - * use preference rank, we take that. Then we multiple by two, yielding - * a sequence like 0, 2, 4, 6, etc. Then if it's IPv6 we add one. This - * makes IPv6 addresses of a given scope outrank IPv4 addresses of the - * same scope -- e.g. 1 outranks 0. This makes us prefer IPv6, but not - * if the address scope/class is of a fundamentally lower rank. */ return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); } @@ -213,7 +207,7 @@ public: /** * @return True if this path needs a heartbeat */ - inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) > ZT_PATH_HEARTBEAT_PERIOD); } + inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } /** * @return Last time we sent something diff --git a/node/Peer.cpp b/node/Peer.cpp index 0cb55fd8..3701d9a1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -134,24 +134,38 @@ void Peer::received( } } - if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address()))) { + if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); - unsigned int slot = 0; + unsigned int slot; if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { slot = _numPaths++; } else { + // First try to replace the worst within the same address family, if possible + int worstSlot = -1; uint64_t worstScore = 0xffffffffffffffffULL; - unsigned int worstPath = ZT_MAX_PEER_NETWORK_PATHS-1; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); - if (s < worstScore) { - worstScore = s; - worstPath = p; + if (_paths[p].path->address().ss_family == path->address().ss_family) { + const uint64_t s = _pathScore(p); + if (s < worstScore) { + worstScore = s; + worstSlot = (int)p; + } + } + } + if (worstSlot >= 0) { + slot = (unsigned int)worstSlot; + } else { + slot = ZT_MAX_PEER_NETWORK_PATHS - 1; + for(unsigned int p=0;p<_numPaths;++p) { + const uint64_t s = _pathScore(p); + if (s < worstScore) { + worstScore = s; + slot = p; + } } } - slot = worstPath; } _paths[slot].lastReceive = now; @@ -164,20 +178,21 @@ void Peer::received( _paths[slot].clusterWeights = 1; #endif } else { - - TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str()); + TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { + // Newer than 1.1.0 can use ECHO, which is smaller Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); outp.armor(_key,true); path->send(RR,outp.data(),outp.size(),now); } else { + // For backward compatibility we send HELLO to ancient nodes sendHELLO(path->localAddress(),path->address(),now); } - } } } else if (trustEstablished) { + // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) _pushDirectPaths(path,now); } @@ -286,7 +301,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ((inetAddressFamily < 0)||(_paths[p].path->address().ss_family == inetAddressFamily)) { + if ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) { const uint64_t s = _pathScore(p); if (s >= best) { best = s; diff --git a/node/Peer.hpp b/node/Peer.hpp index 8286bfff..25ef72b7 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -164,7 +164,7 @@ public: * * @param now Current time * @param inetAddressFamily Keep this address family alive, or -1 for any - * @return True if we have at least one direct path + * @return True if we have at least one direct path of the given family (or any if family is -1) */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); @@ -367,7 +367,7 @@ private: inline uint64_t _pathScore(const unsigned int p) const { - return ( _paths[p].path->lastIn() + + return ( _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + (uint64_t)(_paths[p].clusterWeights * ZT_PEER_PING_PERIOD) ); } diff --git a/node/Utils.cpp b/node/Utils.cpp index 2d9515ee..9d67fc22 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -292,6 +292,7 @@ unsigned int Utils::snprintf(char *buf,unsigned int len,const char *fmt,...) if ((n >= (int)len)||(n < 0)) { if (len) buf[len - 1] = (char)0; + abort(); throw std::length_error("buf[] overflow in Utils::snprintf"); } diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 03c5942d..a24e3eb4 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -165,7 +165,7 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_VirtualNetw static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath *pp,unsigned int count) { - char json[1024]; + char json[2048]; char prefix[32]; if (depth >= sizeof(prefix)) // sanity check -- shouldn't be possible @@ -201,7 +201,7 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath * static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer) { - char json[1024]; + char json[2048]; char prefix[32]; if (depth >= sizeof(prefix)) // sanity check -- shouldn't be possible -- cgit v1.2.3 From 43780742b03ffa69fb1a1868f976ac03edce921b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Sep 2016 11:10:04 -0700 Subject: comments, docs --- node/Path.hpp | 2 ++ node/Peer.cpp | 2 ++ 2 files changed, 4 insertions(+) (limited to 'node/Peer.cpp') diff --git a/node/Path.hpp b/node/Path.hpp index 718e1cdd..8151ed27 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -156,6 +156,8 @@ public: */ inline unsigned int preferenceRank() const { + // This causes us to rank paths in order of IP scope rank (see InetAdddress.hpp) but + // within each IP scope class to prefer IPv6 over IPv4. return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 3701d9a1..110d67fd 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -138,6 +138,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); + // Since this is a new path, figure out where to put it (possibly replacing an old/dead one) unsigned int slot; if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { slot = _numPaths++; @@ -157,6 +158,7 @@ void Peer::received( if (worstSlot >= 0) { slot = (unsigned int)worstSlot; } else { + // If we can't find one with the same family, replace the worst of any family slot = ZT_MAX_PEER_NETWORK_PATHS - 1; for(unsigned int p=0;p<_numPaths;++p) { const uint64_t s = _pathScore(p); -- cgit v1.2.3 From 8a2e8bd5854619c9f701ad300724a1e58d4b6822 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Sep 2016 12:45:28 -0700 Subject: Rework how paths are set as remote cluster preferred. The code is now clearer and cluster preference indications are now very sticky as they should be. --- node/Hashtable.hpp | 2 +- node/Peer.cpp | 38 +++++++++++--------------------------- node/Peer.hpp | 43 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 37 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index c550191e..66f2990a 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -362,7 +362,7 @@ private: template static inline unsigned long _hc(const O &obj) { - return obj.hashCode(); + return (unsigned long)obj.hashCode(); } static inline unsigned long _hc(const uint64_t i) { diff --git a/node/Peer.cpp b/node/Peer.cpp index 110d67fd..ab287d05 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -33,7 +33,6 @@ namespace ZeroTier { static uint32_t _natKeepaliveBuf = 0; Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : - RR(renv), _lastUsed(0), _lastReceive(0), _lastUnicastFrame(0), @@ -41,6 +40,8 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastAnnouncedTo(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), + RR(renv), + _remoteClusterOptimal4(0), _vProto(0), _vMajor(0), _vMinor(0), @@ -50,6 +51,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _latency(0), _directPathPushCutoffCount(0) { + memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); } @@ -126,7 +128,7 @@ void Peer::received( _paths[p].lastReceive = now; _paths[p].path = path; // local address may have changed! #ifdef ZT_ENABLE_CLUSTER - _paths[p].clusterWeights = (unsigned int)(!suboptimalPath); + _paths[p].localClusterSuboptimal = suboptimalPath; #endif pathIsConfirmed = true; break; @@ -173,11 +175,9 @@ void Peer::received( _paths[slot].lastReceive = now; _paths[slot].path = path; #ifdef ZT_ENABLE_CLUSTER - _paths[slot].clusterWeights = (unsigned int)(!suboptimalPath); + _paths[p].localClusterSuboptimal = suboptimalPath; if (RR->cluster) RR->cluster->broadcastHavePeer(_id); -#else - _paths[slot].clusterWeights = 1; #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); @@ -216,26 +216,6 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const return false; } -void Peer::setClusterOptimal(const InetAddress &addr) -{ - Mutex::Lock _l(_paths_m); - - int opt = -1; - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address() == addr) { - opt = (int)p; - break; - } - } - - if (opt >= 0) { // only change anything if we have the optimal path - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == addr.ss_family) - _paths[p].clusterWeights = ((int)p == opt) ? 2 : 0; - } - } -} - bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) { Mutex::Lock _l(_paths_m); @@ -350,7 +330,9 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) if (x != y) { _paths[y].lastReceive = _paths[x].lastReceive; _paths[y].path = _paths[x].path; - _paths[y].clusterWeights = _paths[x].clusterWeights; +#ifdef ZT_ENABLE_CLUSTER + _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal; +#endif } ++y; } @@ -399,7 +381,9 @@ void Peer::clean(uint64_t now) if (y != x) { _paths[y].lastReceive = _paths[x].lastReceive; _paths[y].path = _paths[x].path; - _paths[y].clusterWeights = _paths[x].clusterWeights; +#ifdef ZT_ENABLE_CLUSTER + _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal; +#endif } ++y; } diff --git a/node/Peer.hpp b/node/Peer.hpp index 25ef72b7..cd08e2d7 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -123,11 +123,16 @@ public: /** * Set which known path for an address family is optimal * - * This only modifies paths within the same address family - * * @param addr Address to make exclusive */ - void setClusterOptimal(const InetAddress &addr); + inline void setClusterOptimal(const InetAddress &addr) + { + if (addr.ss_family == AF_INET) { + _remoteClusterOptimal4 = (uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr; + } else if (addr.ss_family == AF_INET6) { + memcpy(_remoteClusterOptimal6,reinterpret_cast(&addr)->sin6_addr.s6_addr,16); + } + } /** * Send via best direct path @@ -367,14 +372,30 @@ private: inline uint64_t _pathScore(const unsigned int p) const { - return ( _paths[p].lastReceive + - (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + - (uint64_t)(_paths[p].clusterWeights * ZT_PEER_PING_PERIOD) ); + uint64_t s = ZT_PEER_PING_PERIOD; + if (_paths[p].path->address().ss_family == AF_INET) { + s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); + } else if (_paths[p].path->address().ss_family == AF_INET6) { + uint64_t clusterWeight = ZT_PEER_PING_PERIOD; + const uint8_t *a = reinterpret_cast(reinterpret_cast(&(_paths[p].path->address()))->sin6_addr.s6_addr); + for(long i=0;i<16;++i) { + if (a[i] != _remoteClusterOptimal6[i]) { + clusterWeight = 0; + break; + } + } + s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + clusterWeight; + } else { + s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); + } +#ifdef ZT_ENABLE_CLUSTER + s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; +#endif + return s; } unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; - - const RuntimeEnvironment *RR; + uint8_t _remoteClusterOptimal6[16]; uint64_t _lastUsed; uint64_t _lastReceive; // direct or indirect uint64_t _lastUnicastFrame; @@ -382,6 +403,8 @@ private: uint64_t _lastAnnouncedTo; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; + const RuntimeEnvironment *RR; + uint32_t _remoteClusterOptimal4; uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; @@ -390,7 +413,9 @@ private: struct { uint64_t lastReceive; SharedPtr path; - unsigned int clusterWeights; +#ifdef ZT_ENABLE_CLUSTER + bool localClusterSuboptimal; +#endif } _paths[ZT_MAX_PEER_NETWORK_PATHS]; Mutex _paths_m; unsigned int _numPaths; -- cgit v1.2.3 From 48a374c82c89b69a71d1922c4396265394e9045f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Sep 2016 14:05:58 -0700 Subject: (1) fix crazy bug introduced in doRENDEZVOUS(), (2) reclaim Paths after paths[] condense, (3) fix an edge case around symmetric NAT and external IP change detection. --- node/IncomingPacket.cpp | 12 ++++++------ node/Path.hpp | 3 ++- node/Peer.cpp | 6 +++++- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a84b2beb..3d2d586e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -283,7 +283,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // VALID -- if we made it here, packet passed identity and authenticity checks! } - if (externalSurfaceAddress) + if ((externalSurfaceAddress)&&(hops() == 0)) RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); @@ -391,7 +391,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - if (externalSurfaceAddress) + if ((externalSurfaceAddress)&&(hops() == 0)) RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; @@ -516,8 +516,8 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< { try { const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr withPeer(RR->topology->getPeer(with)); - if (withPeer) { + const SharedPtr rendezvousWith(RR->topology->getPeer(with)); + if (rendezvousWith) { const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { @@ -525,8 +525,8 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< if (!RR->topology->isUpstream(peer->identity())) { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { - RR->node->putPacket(_path->localAddress(),atAddr,"NATSUX",6,2); // send low-TTL packet to 'open' local NAT(s) - peer->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); + RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); diff --git a/node/Path.hpp b/node/Path.hpp index 8151ed27..129913e1 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -29,6 +29,7 @@ #include "InetAddress.hpp" #include "SharedPtr.hpp" #include "AtomicCounter.hpp" +#include "NonCopyable.hpp" /** * Maximum return value of preferenceRank() @@ -42,7 +43,7 @@ class RuntimeEnvironment; /** * A path across the physical network */ -class Path +class Path : NonCopyable { friend class SharedPtr; diff --git a/node/Peer.cpp b/node/Peer.cpp index ab287d05..c56dbca9 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -339,7 +339,9 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) ++x; } _numPaths = y; - return (y < np); + while (y < ZT_MAX_PEER_NETWORK_PATHS) + _paths[y++].path.zero(); // let go of unused SmartPtr<>'s + return (_numPaths < np); } void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const @@ -390,6 +392,8 @@ void Peer::clean(uint64_t now) ++x; } _numPaths = y; + while (y < ZT_MAX_PEER_NETWORK_PATHS) + _paths[y++].path.zero(); // let go of unused SmartPtr<>'s } bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) -- cgit v1.2.3 From f2d2df2b112c8a644b718abc521af296a83b5337 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Sep 2016 15:06:07 -0700 Subject: Cluster build fix. --- node/Cluster.cpp | 2 +- node/Peer.cpp | 2 +- node/Peer.hpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 933bfb37..2a261e51 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -361,7 +361,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) case CLUSTER_MESSAGE_WANT_PEER: { const Address zeroTierAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; SharedPtr peer(RR->topology->getPeerNoCache(zeroTierAddress)); - if ( (peer) && (peer->hasClusterOptimalPath(RR->node->now())) ) { + if ( (peer) && (peer->hasLocalClusterOptimalPath(RR->node->now())) ) { Buffer<1024> buf; peer->identity().serialize(buf); Mutex::Lock _l2(_members[fromMemberId].lock); diff --git a/node/Peer.cpp b/node/Peer.cpp index c56dbca9..abbbea72 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -175,7 +175,7 @@ void Peer::received( _paths[slot].lastReceive = now; _paths[slot].path = path; #ifdef ZT_ENABLE_CLUSTER - _paths[p].localClusterSuboptimal = suboptimalPath; + _paths[slot].localClusterSuboptimal = suboptimalPath; if (RR->cluster) RR->cluster->broadcastHavePeer(_id); #endif diff --git a/node/Peer.hpp b/node/Peer.hpp index cd08e2d7..3ffabb05 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -289,10 +289,10 @@ public: * @param now Current time * @return True if this peer has at least one active direct path that is not cluster-suboptimal */ - inline bool hasClusterOptimalPath(uint64_t now) const + inline bool hasLocalClusterOptimalPath(uint64_t now) const { for(unsigned int p=0,np=_numPaths;palive(now)) && ((_paths[p].clusterWeights & 1) != 0) ) + if ( (_paths[p].path->alive(now)) && (!_paths[p].localClusterSuboptimal) ) return true; } return false; -- cgit v1.2.3 From b5c86b6ba4112b23e46170fe241b4688532b493e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 11:13:17 -0700 Subject: Bunch more path refactoring. Peers no longer forget paths, but do not normally use expired paths. Expired paths might still be tried if nothing else is reachable. --- include/ZeroTierOne.h | 5 ++ node/Constants.hpp | 18 ++++++-- node/IncomingPacket.cpp | 2 +- node/Node.cpp | 25 ++++------ node/Peer.cpp | 117 ++++++++++++++++++----------------------------- node/Peer.hpp | 46 ++++++++++--------- node/SelfAwareness.cpp | 22 ++++----- node/SelfAwareness.hpp | 1 - node/Switch.cpp | 22 ++++++--- node/Topology.cpp | 5 +- service/ControlPlane.cpp | 6 ++- 11 files changed, 126 insertions(+), 143 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 583abfe4..0c22ae9d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1053,6 +1053,11 @@ typedef struct */ uint64_t trustedPathId; + /** + * Is path expired? + */ + int expired; + /** * Is path preferred? */ diff --git a/node/Constants.hpp b/node/Constants.hpp index ea4c434d..67e6fb58 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -244,17 +244,22 @@ * This is also how often pings will be retried to upstream peers (relays, roots) * constantly until something is heard. */ -#define ZT_PING_CHECK_INVERVAL 9000 +#define ZT_PING_CHECK_INVERVAL 10000 /** * How frequently to send heartbeats over in-use paths */ -#define ZT_PATH_HEARTBEAT_PERIOD 15000 +#define ZT_PATH_HEARTBEAT_PERIOD 10000 /** * Paths are considered inactive if they have not received traffic in this long */ -#define ZT_PATH_ALIVE_TIMEOUT 35000 +#define ZT_PATH_ALIVE_TIMEOUT 25000 + +/** + * Minimum time between attempts to check dead paths to see if they can be re-awakened + */ +#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 /** * Delay between full-fledge pings of directly connected peers @@ -262,10 +267,15 @@ #define ZT_PEER_PING_PERIOD 60000 /** - * Peers forget paths that have not spoken in this long + * Paths are considered expired if they have not produced a real packet in this long */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) +/** + * How often to retry expired paths that we're still remembering + */ +#define ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD (ZT_PEER_PING_PERIOD * 10) + /** * Timeout for overall peer activity (measured from last receive) */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3d2d586e..891607ed 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1163,7 +1163,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt remainingHopsPtr += ZT_ADDRESS_LENGTH; SharedPtr nhp(RR->topology->getPeer(nextHop[h])); if (nhp) { - SharedPtr nhbp(nhp->getBestPath(now)); + SharedPtr nhbp(nhp->getBestPath(now,false)); if ((nhbp)&&(nhbp->alive(now))) nextHopBestPathAddress[h] = nhbp->address(); } diff --git a/node/Node.cpp b/node/Node.cpp index a7d4cfa9..edd48575 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -202,14 +202,6 @@ public: } } - if (!upstream) { - // If I am a root server, only ping other root servers -- roots don't ping "down" - // since that would just be a waste of bandwidth and could potentially cause route - // flapping in Cluster mode. - if (RR->topology->amRoot()) - return; - } - if (upstream) { // "Upstream" devices are roots and relays and get special treatment -- they stay alive // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them. @@ -415,15 +407,16 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; - std::vector< SharedPtr > paths(pi->second->paths()); - SharedPtr bestp(pi->second->getBestPath(_now)); + std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); + SharedPtr bestp(pi->second->getBestPath(_now,false)); p->pathCount = 0; - for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { - memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].lastSend = (*path)->lastOut(); - p->paths[p->pathCount].lastReceive = (*path)->lastIn(); - p->paths[p->pathCount].preferred = (*path == bestp) ? 1 : 0; - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); + for(std::vector< std::pair< SharedPtr,bool > >::iterator path(paths.begin());path!=paths.end();++path) { + memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); + p->paths[p->pathCount].lastSend = path->first->lastOut(); + p->paths[p->pathCount].lastReceive = path->first->lastIn(); + p->paths[p->pathCount].expired = path->second; + p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); ++p->pathCount; } } diff --git a/node/Peer.cpp b/node/Peer.cpp index abbbea72..a2a91769 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,6 +27,14 @@ #include "Cluster.hpp" #include "Packet.hpp" +#ifndef AF_MAX +#if AF_INET > AF_INET6 +#define AF_MAX AF_INET +#else +#define AF_MAX AF_INET6 +#endif +#endif + namespace ZeroTier { // Used to send varying values for NAT keepalive @@ -150,7 +158,7 @@ void Peer::received( uint64_t worstScore = 0xffffffffffffffffULL; for(unsigned int p=0;p<_numPaths;++p) { if (_paths[p].path->address().ss_family == path->address().ss_family) { - const uint64_t s = _pathScore(p); + const uint64_t s = _pathScore(p,now); if (s < worstScore) { worstScore = s; worstSlot = (int)p; @@ -163,7 +171,7 @@ void Peer::received( // If we can't find one with the same family, replace the worst of any family slot = ZT_MAX_PEER_NETWORK_PATHS - 1; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); + const uint64_t s = _pathScore(p,now); if (s < worstScore) { worstScore = s; slot = p; @@ -210,7 +218,7 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address() == addr) && (_paths[p].path->alive(now)) ) + if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) return true; } return false; @@ -223,8 +231,8 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->alive(now)||(forceEvenIfDead)) { - const uint64_t s = _pathScore(p); + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) { + const uint64_t s = _pathScore(p,now); if (s >= best) { best = s; bestp = (int)p; @@ -239,17 +247,19 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE } } -SharedPtr Peer::getBestPath(uint64_t now) +SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); - if (s >= best) { - best = s; - bestp = (int)p; + if ( ((now - _paths[p].lastReceive) < ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { + const uint64_t s = _pathScore(p,now); + if (s >= best) { + best = s; + bestp = (int)p; + } } } @@ -283,8 +293,8 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) { - const uint64_t s = _pathScore(p); + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) { + const uint64_t s = _pathScore(p,now); if (s >= best) { best = s; bestp = (int)p; @@ -293,7 +303,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) } if (bestp >= 0) { - if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { + if ((now - _paths[best].lastReceive) >= ZT_PEER_PING_PERIOD) { sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads @@ -309,39 +319,24 @@ bool Peer::hasActiveDirectPath(uint64_t now) const { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->alive(now)) + if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now))) return true; } return false; } -bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now) +bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) { Mutex::Lock _l(_paths_m); - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if (_paths[x].path->address().ipScope() == scope) { - // Resetting a path means sending a HELLO and then forgetting it. If we - // get OK(HELLO) then it will be re-learned. - sendHELLO(_paths[x].path->localAddress(),_paths[x].path->address(),now); - } else { - if (x != y) { - _paths[y].lastReceive = _paths[x].lastReceive; - _paths[y].path = _paths[x].path; -#ifdef ZT_ENABLE_CLUSTER - _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal; -#endif - } - ++y; + bool resetSomething = false; + for(unsigned int p=0;p<_numPaths;++p) { + if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { + sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); + _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic + resetSomething = true; } - ++x; } - _numPaths = y; - while (y < ZT_MAX_PEER_NETWORK_PATHS) - _paths[y++].path.zero(); // let go of unused SmartPtr<>'s - return (_numPaths < np); + return resetSomething; } void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const @@ -351,17 +346,19 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) int bestp4 = -1,bestp6 = -1; uint64_t best4 = 0ULL,best6 = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _pathScore(p); - if (s >= best4) { - best4 = s; - bestp4 = (int)p; - } - } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _pathScore(p); - if (s >= best6) { - best6 = s; - bestp6 = (int)p; + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) { + if (_paths[p].path->address().ss_family == AF_INET) { + const uint64_t s = _pathScore(p,now); + if (s >= best4) { + best4 = s; + bestp4 = (int)p; + } + } else if (_paths[p].path->address().ss_family == AF_INET6) { + const uint64_t s = _pathScore(p,now); + if (s >= best6) { + best6 = s; + bestp6 = (int)p; + } } } } @@ -372,30 +369,6 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) v6 = _paths[bestp6].path->address(); } -void Peer::clean(uint64_t now) -{ - Mutex::Lock _l(_paths_m); - unsigned int np = _numPaths; - unsigned int x = 0; - unsigned int y = 0; - while (x < np) { - if ((now - _paths[x].lastReceive) <= ZT_PEER_PATH_EXPIRATION) { - if (y != x) { - _paths[y].lastReceive = _paths[x].lastReceive; - _paths[y].path = _paths[x].path; -#ifdef ZT_ENABLE_CLUSTER - _paths[y].localClusterSuboptimal = _paths[x].localClusterSuboptimal; -#endif - } - ++y; - } - ++x; - } - _numPaths = y; - while (y < ZT_MAX_PEER_NETWORK_PATHS) - _paths[y++].path.zero(); // let go of unused SmartPtr<>'s -} - bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) { #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Peer.hpp b/node/Peer.hpp index 3ffabb05..6e1d378f 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -149,9 +149,10 @@ public: * Get the best current direct path * * @param now Current time + * @param includeDead If true, include even expired paths * @return Best current path or NULL if none */ - SharedPtr getBestPath(uint64_t now); + SharedPtr getBestPath(uint64_t now,bool includeExpired); /** * Send a HELLO to this peer at a specified physical address @@ -175,18 +176,22 @@ public: /** * @param now Current time - * @return True if this peer has at least one active direct path + * @return True if this peer has at least one active and alive direct path */ bool hasActiveDirectPath(uint64_t now) const; /** - * Reset paths within a given scope + * Reset paths within a given IP scope and address family * - * @param scope IP scope of paths to reset + * Resetting a path involves sending a HELLO to it and then de-prioritizing + * it vs. other paths. + * + * @param scope IP scope + * @param inetAddressFamily Family e.g. AF_INET * @param now Current time - * @return True if at least one path was forgotten + * @return True if we forgot at least one path */ - bool resetWithinScope(InetAddress::IpScope scope,uint64_t now); + bool resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); /** * Get most recently active path addresses for IPv4 and/or IPv6 @@ -201,21 +206,15 @@ public: void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; /** - * Perform periodic cleaning operations - * * @param now Current time + * @return All known direct paths to this peer and whether they are expired (true == expired) */ - void clean(uint64_t now); - - /** - * @return All known direct paths to this peer (active or inactive) - */ - inline std::vector< SharedPtr > paths() const + inline std::vector< std::pair< SharedPtr,bool > > paths(const uint64_t now) const { - std::vector< SharedPtr > pp; + std::vector< std::pair< SharedPtr,bool > > pp; Mutex::Lock _l(_paths_m); for(unsigned int p=0,np=_numPaths;p,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION)); return pp; } @@ -370,11 +369,12 @@ public: private: bool _pushDirectPaths(const SharedPtr &path,uint64_t now); - inline uint64_t _pathScore(const unsigned int p) const + inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const { - uint64_t s = ZT_PEER_PING_PERIOD; + uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); + if (_paths[p].path->address().ss_family == AF_INET) { - s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); + s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); } else if (_paths[p].path->address().ss_family == AF_INET6) { uint64_t clusterWeight = ZT_PEER_PING_PERIOD; const uint8_t *a = reinterpret_cast(reinterpret_cast(&(_paths[p].path->address()))->sin6_addr.s6_addr); @@ -384,13 +384,15 @@ private: break; } } - s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + clusterWeight; - } else { - s += _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); + s += clusterWeight; } + + s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now); + #ifdef ZT_ENABLE_CLUSTER s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; #endif + return s; } diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index b9ab9d67..6bf50720 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -33,37 +33,31 @@ #include "Switch.hpp" // Entry timeout -- make it fairly long since this is just to prevent stale buildup -#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 3600000 +#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 namespace ZeroTier { class _ResetWithinScope { public: - _ResetWithinScope(uint64_t now,InetAddress::IpScope scope) : + _ResetWithinScope(uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : _now(now), + _family(inetAddressFamily), _scope(scope) {} - inline void operator()(Topology &t,const SharedPtr &p) - { - if (p->resetWithinScope(_scope,_now)) - peersReset.push_back(p); - } + inline void operator()(Topology &t,const SharedPtr &p) { if (p->resetWithinScope(_scope,_family,_now)) peersReset.push_back(p); } std::vector< SharedPtr > peersReset; private: uint64_t _now; + int _family; InetAddress::IpScope _scope; }; SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : RR(renv), - _phy(32) -{ -} - -SelfAwareness::~SelfAwareness() + _phy(128) { } @@ -98,8 +92,8 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc } } - // Reset all paths within this scope - _ResetWithinScope rset(now,(InetAddress::IpScope)scope); + // Reset all paths within this scope and address family + _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); // Send a NOP to all peers for whom we forgot a path. This will cause direct diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index c7bde87e..4bdafeb2 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -36,7 +36,6 @@ class SelfAwareness { public: SelfAwareness(const RuntimeEnvironment *renv); - ~SelfAwareness(); /** * Called when a trusted remote peer informs us of our external network address diff --git a/node/Switch.cpp b/node/Switch.cpp index 28a2564b..21d0b3c9 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -747,14 +747,20 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread bool Switch::_trySend(const Packet &packet,bool encrypt) { - SharedPtr peer(RR->topology->getPeer(packet.destination())); - + const SharedPtr peer(RR->topology->getPeer(packet.destination())); if (peer) { const uint64_t now = RR->node->now(); - SharedPtr viaPath(peer->getBestPath(now)); + // First get the best path, and if it's dead (and this is not a root) + // we attempt to re-activate that path but this packet will flow + // upstream. If the path comes back alive, it will be used in the future. + // For roots we don't do the alive check since roots are not required + // to send heartbeats "down" and because we have to at least try to + // go somewhere. + + SharedPtr viaPath(peer->getBestPath(now,false)); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) { - if ((now - viaPath->lastOut()) > 5000) { + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) >> 2,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ECHO); outp.armor(peer->key(),true); viaPath->send(RR,outp.data(),outp.size(),now); @@ -763,8 +769,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) } if (!viaPath) { SharedPtr relay(RR->topology->getBestRoot()); - if ( (!relay) || (!(viaPath = relay->getBestPath(now))) ) - return false; + if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { + if (!(viaPath = peer->getBestPath(now,true))) + return false; + } } Packet tmp(packet); @@ -787,7 +795,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) ++fragsRemaining; - unsigned int totalFragments = fragsRemaining + 1; + const unsigned int totalFragments = fragsRemaining + 1; for(unsigned int fno=1;fno *p = (SharedPtr *)0; while (i.next(a,p)) { - if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) { + if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) _peers.erase(*a); - } else { - (*p)->clean(now); - } } } { diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index a24e3eb4..b443a7fa 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -183,14 +183,16 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath * "%s\t\"address\": \"%s\",\n" "%s\t\"lastSend\": %llu,\n" "%s\t\"lastReceive\": %llu,\n" - "%s\t\"active\": true,\n" + "%s\t\"active\": %s,\n" + "%s\t\"expired\": %s,\n" "%s\t\"preferred\": %s,\n" "%s\t\"trustedPathId\": %llu\n" "%s}", prefix,_jsonEscape(reinterpret_cast(&(pp[i].address))->toString()).c_str(), prefix,pp[i].lastSend, prefix,pp[i].lastReceive, - prefix, + prefix,(pp[i].expired != 0) ? "false" : "true", + prefix,(pp[i].expired == 0) ? "false" : "true", prefix,(pp[i].preferred == 0) ? "false" : "true", prefix,pp[i].trustedPathId, prefix); -- cgit v1.2.3 From ff9f8b1c2b12cf11205a040748cbc9f223a67e19 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 11:15:36 -0700 Subject: Typo fix. --- node/Peer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index a2a91769..c24d4246 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -303,7 +303,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) } if (bestp >= 0) { - if ((now - _paths[best].lastReceive) >= ZT_PEER_PING_PERIOD) { + if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads -- cgit v1.2.3 From a7d988745bcca4a0f9c838ec493e658b098d241d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 12:01:03 -0700 Subject: Use ECHO instead of HELLO where possible. --- node/IncomingPacket.cpp | 6 +++--- node/Path.hpp | 7 +++++++ node/Peer.cpp | 31 ++++++++++++++++++------------- node/Peer.hpp | 11 +++++++++++ 4 files changed, 39 insertions(+), 16 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 891607ed..0857fb3d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -526,7 +526,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->sendHELLO(_path->localAddress(),atAddr,RR->node->now()); + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1050,7 +1050,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->sendHELLO(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1069,7 +1069,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->sendHELLO(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } diff --git a/node/Path.hpp b/node/Path.hpp index 129913e1..27cff645 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -137,6 +137,13 @@ public: */ bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now); + /** + * Manually update last sent time + * + * @param t Time of send + */ + inline void sent(const uint64_t t) { _lastOut = t; } + /** * @return Address of local side of this path or NULL if unspecified */ diff --git a/node/Peer.cpp b/node/Peer.cpp index c24d4246..3d3ca247 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -189,16 +189,8 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - - if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { - // Newer than 1.1.0 can use ECHO, which is smaller - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); - outp.armor(_key,true); - path->send(RR,outp.data(),outp.size(),now); - } else { - // For backward compatibility we send HELLO to ancient nodes - sendHELLO(path->localAddress(),path->address(),now); - } + attemptToContactAt(path->localAddress(),path->address(),now); + path->sent(now); } } } else if (trustEstablished) { @@ -254,7 +246,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) < ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { + if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { const uint64_t s = _pathScore(p,now); if (s >= best) { best = s; @@ -286,6 +278,17 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } +void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) +{ + if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); + outp.armor(_key,true); + RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + } else { + sendHELLO(localAddr,atAddress,now); + } +} + bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); @@ -304,7 +307,8 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { - sendHELLO(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + _paths[bestp].path->sent(now); } else if (_paths[bestp].path->needsHeartbeat(now)) { _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads _paths[bestp].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); @@ -331,7 +335,8 @@ bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin bool resetSomething = false; for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - sendHELLO(_paths[p].path->localAddress(),_paths[p].path->address(),now); + attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now); + _paths[p].path->sent(now); _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic resetSomething = true; } diff --git a/node/Peer.hpp b/node/Peer.hpp index 6e1d378f..7a7453ae 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -165,6 +165,17 @@ public: */ void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + /** + * Send ECHO (or HELLO for older peers) to this peer at the given address + * + * No statistics or sent times are updated here. + * + * @param localAddr Local address + * @param atAddress Destination address + * @param now Current time + */ + void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + /** * Send pings or keepalives depending on configured timeouts * -- cgit v1.2.3 From 1908aa55f51d63bceb7ed5d4211a4274d732de63 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 15:15:52 -0700 Subject: Refactor MULTICAST_LIKE pushing to eliminate redundant and unnecessary pushes and simplify code. --- node/Constants.hpp | 28 +++++------- node/IncomingPacket.cpp | 93 +++++++++++++++++++++------------------ node/Membership.cpp | 7 ++- node/Membership.hpp | 49 ++++++++++++--------- node/Network.cpp | 115 ++++++++++++++++++++++-------------------------- node/Network.hpp | 46 ++++++------------- node/Node.cpp | 6 +-- node/Peer.cpp | 21 +++------ node/Peer.hpp | 19 ++++---- 9 files changed, 182 insertions(+), 202 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 67e6fb58..a625b480 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -180,14 +180,14 @@ #define ZT_PEER_SECRET_KEY_LENGTH 32 /** - * How often Topology::clean() and Network::clean() and similar are called, in ms + * Minimum delay between timer task checks to prevent thrashing */ -#define ZT_HOUSEKEEPING_PERIOD 120000 +#define ZT_CORE_TIMER_TASK_GRANULARITY 500 /** - * Overriding granularity for timer tasks to prevent CPU-intensive thrashing on every packet + * How often Topology::clean() and Network::clean() and similar are called, in ms */ -#define ZT_CORE_TIMER_TASK_GRANULARITY 500 +#define ZT_HOUSEKEEPING_PERIOD 120000 /** * How long to remember peer records in RAM if they haven't been used @@ -226,6 +226,11 @@ */ #define ZT_MULTICAST_LIKE_EXPIRE 600000 +/** + * Period for multicast LIKE announcements + */ +#define ZT_MULTICAST_ANNOUNCE_PERIOD 120000 + /** * Delay between explicit MULTICAST_GATHER requests for a given multicast channel */ @@ -239,12 +244,9 @@ #define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000 /** - * Delay between scans of the topology active peer DB for peers that need ping - * - * This is also how often pings will be retried to upstream peers (relays, roots) - * constantly until something is heard. + * Delay between checks of peer pings, etc., and also related housekeeping tasks */ -#define ZT_PING_CHECK_INVERVAL 10000 +#define ZT_PING_CHECK_INVERVAL 5000 /** * How frequently to send heartbeats over in-use paths @@ -298,14 +300,6 @@ */ #define ZT_MIN_UNITE_INTERVAL 30000 -/** - * Delay between initial direct NAT-t packet and more aggressive techniques - * - * This may also be a delay before sending the first packet if we determine - * that we should wait for the remote to initiate rendezvous first. - */ -#define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000 - /** * Sanity limit on maximum bridge routes * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0857fb3d..97e1abe3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,6 +42,8 @@ namespace ZeroTier { +static const SharedPtr NULL_NETWORK; + bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) { const Address sourceAddress(source()); @@ -88,7 +90,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; case Packet::VERB_HELLO: return _doHELLO(RR,peer); @@ -172,7 +174,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -339,7 +341,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -461,7 +463,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -505,7 +507,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -537,7 +539,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } else { TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -547,25 +549,27 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID))); + const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + bool approved = false; if (network) { 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(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,false); } else { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),network->id()); + const MAC sourceMac(peer->address(),nwid); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,true); + RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + approved = true; // this means approved on the network in general, not this packet per se } } } else { - TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved,network); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -575,7 +579,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID))); + const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); if (network) { if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; @@ -590,7 +595,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

isAllowed(peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,network); return true; } @@ -602,37 +607,38 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } switch (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { case 1: - if (from != MAC(peer->address(),network->id())) { + if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } } // fall through -- 2 means accept regardless of bridging checks or other restrictions case 2: - RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + RR->node->putFrame(nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); break; } - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); } } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); } } catch ( ... ) { TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -651,7 +657,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); - peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -670,7 +676,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -719,7 +725,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -817,7 +823,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk,NULL_NETWORK); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -839,7 +845,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons network->requestConfiguration(); } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } @@ -851,7 +857,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -902,7 +908,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -932,7 +938,7 @@ 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(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,network); return true; } @@ -959,28 +965,28 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } - if (from != MAC(peer->address(),network->id())) { + if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay return true; } } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { - RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); + RR->node->putFrame(nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } } @@ -998,9 +1004,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); } else { - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1016,7 +1022,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // First, subject this to a rate limit if (!peer->shouldRespondToDirectPathPush(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } @@ -1079,7 +1085,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1123,7 +1129,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } vlf += signatureLength; @@ -1140,12 +1146,12 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); return true; } @@ -1216,7 +1222,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1261,7 +1267,8 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S } RR->node->postCircuitTestReport(&report); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false,NULL_NETWORK); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1322,7 +1329,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const break; } - peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false,NULL_NETWORK); } else { TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Membership.cpp b/node/Membership.cpp index e809e2bd..74a01350 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -89,21 +89,26 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint } } -int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com) +int Membership::addCredential(const RuntimeEnvironment *RR,const Network *network,const CertificateOfMembership &com) { if (_com == com) { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); + sendCredentialsIfNeeded(RR,RR->node->now(),com.issuedTo(),network->config(),(const Capability *)0); return 0; } + const int vr = com.verify(RR); + if (vr == 0) { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); if (com.timestamp().first > _com.timestamp().first) { _com = com; } + sendCredentialsIfNeeded(RR,RR->node->now(),com.issuedTo(),network->config(),(const Capability *)0); } else { TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (%d)",com.issuedTo().toString().c_str(),com.networkId(),vr); } + return vr; } diff --git a/node/Membership.hpp b/node/Membership.hpp index 293fa4d8..324f92a6 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -31,15 +31,10 @@ #include "Hashtable.hpp" #include "NetworkConfig.hpp" -// Expiration time for capability and tag cache -#define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA - -// Expiration time for Memberships (used in Network::clean()) -#define ZT_MEMBERSHIP_EXPIRATION_TIME ZT_PEER_IN_MEMORY_EXPIRATION - namespace ZeroTier { class RuntimeEnvironment; +class Network; /** * A container for certificates of membership and other network credentials @@ -107,6 +102,7 @@ public: friend class CapabilityIterator; Membership() : + _lastUpdatedMulticast(0), _lastPushAttempt(0), _lastPushedCom(0), _blacklistBefore(0), @@ -130,6 +126,21 @@ public: */ void sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap); + /** + * Check whether we should push MULTICAST_LIKEs to this peer + * + * @param now Current time + * @return True if we should update multicasts + */ + inline bool shouldLikeMulticasts(const uint64_t now) const { return ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD); } + + /** + * Set time we last updated multicasts for this peer + * + * @param now Current time + */ + inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; } + /** * @param nconf Our network config * @return True if this peer is allowed on this network at all @@ -206,9 +217,12 @@ public: /** * Validate and add a credential if signature is okay and it's otherwise good * + * @param RR Runtime environment + * @param network Network that owns this Membership + * @param com Certificate of membership * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com); + int addCredential(const RuntimeEnvironment *RR,const Network *network,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good @@ -237,20 +251,15 @@ public: /** * Clean up old or stale entries * - * @return Time of most recent activity in this Membership + * @param nconf Network config */ - inline uint64_t clean(const uint64_t now) + inline void clean(const NetworkConfig &nconf) { - uint64_t lastAct = _lastPushedCom; - for(std::map::iterator i(_caps.begin());i!=_caps.end();) { - const uint64_t la = std::max(i->second.lastPushed,i->second.lastReceived); - if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) { + if (!isCredentialTimestampValid(nconf,i->second.cap)) { _caps.erase(i++); } else { ++i; - if (la > lastAct) - lastAct = la; } } @@ -258,17 +267,15 @@ public: TState *ts = (TState *)0; Hashtable::Iterator tsi(_tags); while (tsi.next(i,ts)) { - const uint64_t la = std::max(ts->lastPushed,ts->lastReceived); - if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) + if (!isCredentialTimestampValid(nconf,ts->tag)) _tags.erase(*i); - else if (la > lastAct) - lastAct = la; } - - return lastAct; } private: + // Last time we pushed MULTICAST_LIKE(s) + uint64_t _lastUpdatedMulticast; + // Last time we checked if credential push was needed uint64_t _lastPushAttempt; diff --git a/node/Network.cpp b/node/Network.cpp index b18a3b22..7c2a4084 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -577,6 +577,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : RR(renv), _uPtr(uptr), _id(nwid), + _lastAnnouncedMulticastGroupsUpstream(0), _mac(renv->identity.address(),nwid), _portInitialized(false), _inboundConfigPacketId(0), @@ -872,8 +873,8 @@ void Network::multicastSubscribe(const MulticastGroup &mg) return; _myMulticastGroups.push_back(mg); std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end()); + _announceMulticastGroups(&mg); } - _announceMulticastGroups(); } void Network::multicastUnsubscribe(const MulticastGroup &mg) @@ -888,20 +889,6 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.swap(nmg); } -bool Network::tryAnnounceMulticastGroupsTo(const SharedPtr &peer) -{ - Mutex::Lock _l(_lock); - if ( - (_isAllowed(peer)) || - (peer->address() == this->controller()) || - (RR->topology->isUpstream(peer->identity())) - ) { - _announceMulticastGroupsTo(peer,_allMulticastGroups()); - return true; - } - return false; -} - bool Network::applyConfiguration(const NetworkConfig &conf) { if (_destroyed) // sanity check @@ -1094,8 +1081,9 @@ void Network::clean() Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ((now - m->clean(now)) > ZT_MEMBERSHIP_EXPIRATION_TIME) - _memberships.erase(*a); + if (RR->topology->getPeerNoCache(*a)) + m->clean(_config); + else _memberships.erase(*a); } } } @@ -1143,7 +1131,7 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _announceMulticastGroups(); + _announceMulticastGroups(&mg); } void Network::destroy() @@ -1223,61 +1211,66 @@ bool Network::_isAllowed(const SharedPtr &peer) const return false; } -class _MulticastAnnounceAll +void Network::_announceMulticastGroups(const MulticastGroup *const onlyThis) { -public: - _MulticastAnnounceAll(const RuntimeEnvironment *renv,Network *nw) : - _now(renv->node->now()), - _controller(nw->controller()), - _network(nw), - _anchors(nw->config().anchors()), - _upstreamAddresses(renv->topology->upstreamAddresses()) - {} - inline void operator()(Topology &t,const SharedPtr &p) - { - if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed, which isn't terrible but is a bit stupid - (p->address() == _controller) || - (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),p->address()) != _upstreamAddresses.end()) || - (std::find(_anchors.begin(),_anchors.end(),p->address()) != _anchors.end()) ) { - peers.push_back(p); + // Assumes _lock is locked + const uint64_t now = RR->node->now(); + + std::vector groups; + if (onlyThis) + groups.push_back(*onlyThis); + else groups = _allMulticastGroups(); + + if ((onlyThis)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { + if (!onlyThis) + _lastAnnouncedMulticastGroupsUpstream = now; + + // Announce multicast groups to upstream peers (roots, etc.) and also send + // them our COM so that MULTICAST_GATHER can be authenticated properly. + const std::vector

upstreams(RR->topology->upstreamAddresses()); + for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { + if ((_config.isPrivate())&&(_config.com)) { + Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + _config.com.serialize(outp); + outp.append((uint8_t)0x00); + RR->sw->send(outp,true); + } + _announceMulticastGroupsTo(*a,groups); } } - std::vector< SharedPtr > peers; -private: - const uint64_t _now; - const Address _controller; - Network *const _network; - const std::vector
_anchors; - const std::vector
_upstreamAddresses; -}; -void Network::_announceMulticastGroups() -{ - // Assumes _lock is locked - std::vector allMulticastGroups(_allMulticastGroups()); - _MulticastAnnounceAll gpfunc(RR,this); - RR->topology->eachPeer<_MulticastAnnounceAll &>(gpfunc); - for(std::vector< SharedPtr >::const_iterator i(gpfunc.peers.begin());i!=gpfunc.peers.end();++i) - _announceMulticastGroupsTo(*i,allMulticastGroups); -} -void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std::vector &allMulticastGroups) -{ - // Assumes _lock is locked + // Make sure that all "network anchors" have Membership records so we will + // push multicasts to them. + const std::vector
anchors(_config.anchors()); + for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) + _memberships[*a]; - // Anyone we announce multicast groups to will need our COM to authenticate GATHER requests. + // Send MULTICAST_LIKE(s) to all members of this network { - Membership *m = _memberships.get(peer->address()); - if (m) - m->sendCredentialsIfNeeded(RR,RR->node->now(),peer->address(),_config,(const Capability *)0); + Address *a = (Address *)0; + Membership *m = (Membership *)0; + Hashtable::Iterator i(_memberships); + while (i.next(a,m)) { + if ((onlyThis)||(m->shouldLikeMulticasts(now))) { + if (!onlyThis) + m->likingMulticasts(now); + m->sendCredentialsIfNeeded(RR,RR->node->now(),*a,_config,(const Capability *)0); + _announceMulticastGroupsTo(*a,groups); + } + } } +} - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); +void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups) +{ + // Assumes _lock is locked + Packet outp(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { outp.compress(); RR->sw->send(outp,true); - outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); + outp.reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } // network ID, MAC, ADI @@ -1295,7 +1288,6 @@ void Network::_announceMulticastGroupsTo(const SharedPtr &peer,const std:: std::vector Network::_allMulticastGroups() const { // Assumes _lock is locked - std::vector mgs; mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1); mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end()); @@ -1304,7 +1296,6 @@ std::vector Network::_allMulticastGroups() const mgs.push_back(Network::BROADCAST); std::sort(mgs.begin(),mgs.end()); mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end()); - return mgs; } diff --git a/node/Network.hpp b/node/Network.hpp index 45a51bf2..4d0e25b7 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -190,14 +190,6 @@ public: */ void multicastUnsubscribe(const MulticastGroup &mg); - /** - * Announce multicast groups to a peer if that peer is authorized on this network - * - * @param peer Peer to try to announce multicast groups to - * @return True if peer was authorized and groups were announced - */ - bool tryAnnounceMulticastGroupsTo(const SharedPtr &peer); - /** * Apply a NetworkConfig to this network * @@ -272,6 +264,15 @@ public: */ void clean(); + /** + * Announce multicast groups to all members, anchors, etc. + */ + inline void announceMulticastGroups() + { + Mutex::Lock _l(_lock); + _announceMulticastGroups((const MulticastGroup *)0); + } + /** * @return Time of last updated configuration or 0 if none */ @@ -298,23 +299,10 @@ public: /** * Get current network config * - * This returns a const reference to the network config in place, which is safe - * to concurrently access but *may* change during access. Normally this isn't a - * problem, but if it is use configCopy(). - * * @return Network configuration (may be a null config if we don't have one yet) */ inline const NetworkConfig &config() const { return _config; } - /** - * @return A thread-safe copy of our NetworkConfig instead of a const reference - */ - inline NetworkConfig configCopy() const - { - Mutex::Lock _l(_lock); - return _config; - } - /** * @return True if this network has a valid config */ @@ -323,7 +311,7 @@ public: /** * @return Ethernet MAC address for this network's local interface */ - inline const MAC &mac() const throw() { return _mac; } + inline const MAC &mac() const { return _mac; } /** * Find the node on this network that has this MAC behind it (if any) @@ -365,7 +353,7 @@ public: if (com.networkId() != _id) return -1; Mutex::Lock _l(_lock); - return _memberships[com.issuedTo()].addCredential(RR,com); + return _memberships[com.issuedTo()].addCredential(RR,this,com); } /** @@ -417,24 +405,18 @@ public: */ inline void **userPtr() throw() { return &_uPtr; } - inline bool operator==(const Network &n) const throw() { return (_id == n._id); } - inline bool operator!=(const Network &n) const throw() { return (_id != n._id); } - inline bool operator<(const Network &n) const throw() { return (_id < n._id); } - inline bool operator>(const Network &n) const throw() { return (_id > n._id); } - inline bool operator<=(const Network &n) const throw() { return (_id <= n._id); } - inline bool operator>=(const Network &n) const throw() { return (_id >= n._id); } - private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _isAllowed(const SharedPtr &peer) const; - void _announceMulticastGroups(); - void _announceMulticastGroupsTo(const SharedPtr &peer,const std::vector &allMulticastGroups); + void _announceMulticastGroups(const MulticastGroup *const onlyThis); + void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; const RuntimeEnvironment *RR; void *_uPtr; uint64_t _id; + uint64_t _lastAnnouncedMulticastGroupsUpstream; MAC _mac; // local MAC address volatile bool _portInitialized; diff --git a/node/Node.cpp b/node/Node.cpp index edd48575..233ddc02 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -261,13 +261,11 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB { Mutex::Lock _l(_networks_m); for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { - if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) { + if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - } + n->second->announceMulticastGroups(); } } - - // Request updated configuration for networks that need it for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) (*n)->requestConfiguration(); diff --git a/node/Peer.cpp b/node/Peer.cpp index 3d3ca247..43daeb13 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -45,7 +45,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), - _lastAnnouncedTo(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), RR(renv), @@ -66,12 +65,13 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident void Peer::received( const SharedPtr &path, - unsigned int hops, - uint64_t packetId, - Packet::Verb verb, - uint64_t inRePacketId, - Packet::Verb inReVerb, - const bool trustEstablished) + const unsigned int hops, + const uint64_t packetId, + const Packet::Verb verb, + const uint64_t inRePacketId, + const Packet::Verb inReVerb, + const bool trustEstablished, + const SharedPtr &network) { const uint64_t now = RR->node->now(); @@ -197,13 +197,6 @@ void Peer::received( // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) _pushDirectPaths(path,now); } - - if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { - _lastAnnouncedTo = now; - const std::vector< SharedPtr > networks(RR->node->allNetworks()); - for(std::vector< SharedPtr >::const_iterator n(networks.begin());n!=networks.end();++n) - (*n)->tryAnnounceMulticastGroupsTo(SharedPtr(this)); - } } bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const diff --git a/node/Peer.hpp b/node/Peer.hpp index 7a7453ae..19767a70 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -45,6 +45,8 @@ namespace ZeroTier { +class Network; + /** * Peer on P2P Network (virtual layer 1) */ @@ -103,15 +105,17 @@ public: * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established + * @param network Network to which this packet pertains or NULL if none */ void received( const SharedPtr &path, - unsigned int hops, - uint64_t packetId, - Packet::Verb verb, - uint64_t inRePacketId, - Packet::Verb inReVerb, - const bool trustEstablished); + const unsigned int hops, + const uint64_t packetId, + const Packet::Verb verb, + const uint64_t inRePacketId, + const Packet::Verb inReVerb, + const bool trustEstablished, + const SharedPtr &network); /** * @param now Current time @@ -407,13 +411,12 @@ private: return s; } - unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; + uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t _remoteClusterOptimal6[16]; uint64_t _lastUsed; uint64_t _lastReceive; // direct or indirect uint64_t _lastUnicastFrame; uint64_t _lastMulticastFrame; - uint64_t _lastAnnouncedTo; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; const RuntimeEnvironment *RR; -- cgit v1.2.3 From c7a4da3dd3bb429b5d2f69373388b3b22a6544cb Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Sep 2016 15:24:53 -0700 Subject: Turns out we do not need to pass network to receive(). --- node/IncomingPacket.cpp | 70 ++++++++++++++++++++++++------------------------- node/Peer.cpp | 3 +-- node/Peer.hpp | 6 +---- 3 files changed, 36 insertions(+), 43 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 97e1abe3..39f077ff 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,8 +42,6 @@ namespace ZeroTier { -static const SharedPtr NULL_NETWORK; - bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) { const Address sourceAddress(source()); @@ -90,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; case Packet::VERB_HELLO: return _doHELLO(RR,peer); @@ -174,7 +172,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -341,7 +339,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -463,7 +461,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -507,7 +505,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -539,7 +537,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } else { TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -569,7 +567,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved,network); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -595,7 +593,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

isAllowed(peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,network); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -607,7 +605,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -618,13 +616,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -634,11 +632,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,network); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -657,7 +655,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); - peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -676,7 +674,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,nwid,group,peer->address()); } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -725,7 +723,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -823,7 +821,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk,NULL_NETWORK); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -845,7 +843,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons network->requestConfiguration(); } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); return true; } @@ -857,7 +855,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -908,7 +906,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } @@ -938,7 +936,7 @@ 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(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,network); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -965,12 +963,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -979,7 +977,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); // trustEstablished because COM is okay + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } @@ -1004,9 +1002,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,network); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1022,7 +1020,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // First, subject this to a rate limit if (!peer->shouldRespondToDirectPathPush(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1085,7 +1083,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1129,7 +1127,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1146,12 +1144,12 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1222,7 +1220,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1268,7 +1266,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S RR->node->postCircuitTestReport(&report); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -1329,7 +1327,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const break; } - peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false,NULL_NETWORK); + peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false); } else { TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 43daeb13..58faab3b 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -70,8 +70,7 @@ void Peer::received( const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished, - const SharedPtr &network) + const bool trustEstablished) { const uint64_t now = RR->node->now(); diff --git a/node/Peer.hpp b/node/Peer.hpp index 19767a70..2e64fb4d 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -45,8 +45,6 @@ namespace ZeroTier { -class Network; - /** * Peer on P2P Network (virtual layer 1) */ @@ -105,7 +103,6 @@ public: * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established - * @param network Network to which this packet pertains or NULL if none */ void received( const SharedPtr &path, @@ -114,8 +111,7 @@ public: const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished, - const SharedPtr &network); + const bool trustEstablished); /** * @param now Current time -- cgit v1.2.3 From 0d4109a9f1f119e336d73039251ad17c0e2a56f4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Sep 2016 08:43:58 -0700 Subject: More refactoring to clean up code, and add a gate function to make sure we do not handle OK packets we did not expect. This hardens up a few potential edge cases around security, since such messages might be used to e.g. pollute a cache and DOS under certain conditions. --- controller/EmbeddedNetworkController.cpp | 2 - include/ZeroTierOne.h | 12 +-- node/IncomingPacket.cpp | 156 ++++++++++++++++++------------- node/Membership.hpp | 6 +- node/Multicaster.cpp | 1 + node/Network.cpp | 10 ++ node/Network.hpp | 6 ++ node/Node.cpp | 3 + node/Node.hpp | 34 +++++++ node/OutboundMulticast.cpp | 1 + node/Packet.hpp | 5 +- node/Peer.cpp | 2 + node/Switch.cpp | 11 +-- 13 files changed, 168 insertions(+), 81 deletions(-) (limited to 'node/Peer.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index cf6bd7c9..79560dcc 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1585,7 +1585,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes "\t\"upstream\": \"%.10llx\"," ZT_EOL_S "\t\"current\": \"%.10llx\"," ZT_EOL_S "\t\"receivedTimestamp\": %llu," ZT_EOL_S - "\t\"remoteTimestamp\": %llu," ZT_EOL_S "\t\"sourcePacketId\": \"%.16llx\"," ZT_EOL_S "\t\"flags\": %llu," ZT_EOL_S "\t\"sourcePacketHopCount\": %u," ZT_EOL_S @@ -1606,7 +1605,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes (unsigned long long)report->upstream, (unsigned long long)report->current, (unsigned long long)OSUtils::now(), - (unsigned long long)report->remoteTimestamp, (unsigned long long)report->sourcePacketId, (unsigned long long)report->flags, report->sourcePacketHopCount, diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 0c22ae9d..633db7cf 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -154,6 +154,11 @@ extern "C" { */ #define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 8 +/** + * Circuit test report flag: upstream peer authorized in path (e.g. by network COM) + */ +#define ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH 0x0000000000000001ULL + /** * Maximum number of cluster members (and max member ID plus one) */ @@ -1218,18 +1223,13 @@ typedef struct { */ uint64_t timestamp; - /** - * Timestamp on remote device - */ - uint64_t remoteTimestamp; - /** * 64-bit packet ID of packet received by the reporting device */ uint64_t sourcePacketId; /** - * Flags (currently unused, will be zero) + * Flags */ uint64_t flags; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ac04ce96..c8364415 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -156,6 +156,17 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; + case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + network->config().com.serialize(outp); + outp.append((uint8_t)0); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + } + } break; + case Packet::ERROR_NETWORK_ACCESS_DENIED_: { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) @@ -163,10 +174,12 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr } break; case Packet::ERROR_UNWANTED_MULTICAST: { - uint64_t nwid = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); - MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",nwid,peer->address().toString().c_str(),mg.toString().c_str()); - RR->mc->remove(nwid,mg,peer->address()); + SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network)&&(network->gate(peer,verb(),packetId()))) { + MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); + TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); + RR->mc->remove(network->id(),mg,peer->address()); + } } break; default: break; @@ -352,7 +365,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); + if (!RR->node->expectingReplyTo(inRePacketId)) { + TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); + return true; + } + + //TRACE("%s(%s): OK(%s)",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { @@ -424,10 +442,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); - const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + SharedPtr network(RR->node->network(nwid)); + if ((network)&&(network->gate(peer,verb(),packetId()))) { + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); + //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); + const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + } } break; case Packet::VERB_MULTICAST_FRAME: { @@ -437,24 +458,26 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); - unsigned int offset = 0; + SharedPtr network(RR->node->network(nwid)); + if (network) { + unsigned int offset = 0; - 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); - if (com) { - SharedPtr network(RR->node->network(com.networkId())); - if (network) + 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); + if (com) network->addCredential(com); } - } - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + if (network->gate(peer,verb(),packetId())) { + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); offset += 4; + unsigned int count = at(offset); offset += 2; + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + } + } } } break; @@ -515,27 +538,29 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(with)); - if (rendezvousWith) { - const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); - const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; - if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { - const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (!RR->topology->isUpstream(peer->identity())) { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { - RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); - TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + if (!RR->topology->isUpstream(peer->identity())) { + TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); + } else { + const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + const SharedPtr rendezvousWith(RR->topology->getPeer(with)); + if (rendezvousWith) { + const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); + const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; + if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { + const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); + if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { + RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); + TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + } else { + TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + } } else { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); + TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); } } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); + TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } - } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { @@ -549,25 +574,25 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr try { const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); - bool approved = false; + bool trustEstablished = false; if (network) { - if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - } else { + if (!network->gate(peer,verb(),packetId())) { + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + } else { + trustEstablished = true; + if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); const MAC sourceMac(peer->address(),nwid); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); - approved = true; // this means approved on the network in general, not this packet per se } } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved); + peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -580,23 +605,23 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); if (network) { - if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; + const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; - unsigned int comLen = 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); - if (com) - network->addCredential(com); - } + unsigned int comLen = 0; + if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers + CertificateOfMembership com; + comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); + if (com) + network->addCredential(com); + } - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); - return true; - } + if (!network->gate(peer,verb(),packetId())) { + TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + return true; + } + if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); @@ -604,7 +629,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -1139,6 +1164,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt // Add length of second "additional fields" section. vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf); + uint64_t reportFlags = 0; + // Check credentials (signature already verified) if (originatorCredentialNetworkId) { SharedPtr network(RR->node->network(originatorCredentialNetworkId)); @@ -1147,6 +1174,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } + if (network->gate(peer,verb(),packetId())) + reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); @@ -1188,7 +1217,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED); outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED); outp.append((uint16_t)0); // error code, currently unused - outp.append((uint64_t)0); // flags, currently unused + outp.append((uint64_t)reportFlags); outp.append((uint64_t)packetId()); peer->address().appendTo(outp); outp.append((uint8_t)hops()); @@ -1237,7 +1266,6 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); - report.remoteTimestamp = at(ZT_PACKET_IDX_PAYLOAD + 16); report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58 diff --git a/node/Membership.hpp b/node/Membership.hpp index 55355fda..d67c6822 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -163,8 +163,10 @@ public: return true; if (_com) { const uint64_t a = _com.timestamp().first; - const std::pair b(nconf.com.timestamp()); - return ((a <= b.first) ? ((b.first - a) <= ZT_PEER_ACTIVITY_TIMEOUT) : true); + if ((_blacklistBefore)&&(a <= _blacklistBefore)) + return false; + const uint64_t b = nconf.com.timestamp().first; + return ((a <= b) ? ((b - a) <= ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA) : true); } return false; } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index a6bff6aa..36d7d2d0 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -253,6 +253,7 @@ void Multicaster::send( outp.append((uint32_t)gatherLimit); if (com) com->serialize(outp); + RR->node->expectReplyTo(outp.packetId()); RR->sw->send(outp,true); } } diff --git a/node/Network.cpp b/node/Network.cpp index 2a5f213c..710e70dd 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1054,6 +1054,7 @@ void Network::requestConfiguration() } else { outp.append((unsigned char)0,16); } + RR->node->expectReplyTo(outp.packetId()); outp.compress(); RR->sw->send(outp,true); @@ -1092,6 +1093,15 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } +bool Network::recentlyAllowedOnNetwork(const SharedPtr &peer) const +{ + Mutex::Lock _l(_lock); + const Membership *m = _memberships.get(peer->address()); + if (m) + return m->recentlyAllowedOnNetwork(_config); + return false; +} + void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index c80f1cba..e8d6e2a5 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -257,6 +257,12 @@ public: */ bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + /** + * @param peer Peer to check + * @return True if peer has recently been a valid member of this network + */ + bool recentlyAllowedOnNetwork(const SharedPtr &peer) const; + /** * Perform cleanup and possibly save state */ diff --git a/node/Node.cpp b/node/Node.cpp index 415385f7..e8279c62 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -75,6 +75,9 @@ Node::Node( { _online = false; + memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); + memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); + // Use Salsa20 alone as a high-quality non-crypto PRNG { char foo[32]; diff --git a/node/Node.hpp b/node/Node.hpp index 3c0a5e92..315b5248 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -44,6 +44,10 @@ #define TRACE(f,...) {} #endif +// Bit mask for "expecting reply" hash +#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 +#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 + namespace ZeroTier { /** @@ -250,6 +254,33 @@ public: void postCircuitTestReport(const ZT_CircuitTestReport *report); void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); + /** + * Register that we are expecting a reply to a packet ID + * + * @param packetId Packet ID to expect reply to + */ + inline void expectReplyTo(const uint64_t packetId) + { + const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + _expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = packetId; + } + + /** + * Check whether a given packet ID is something we are expecting a reply to + * + * @param packetId Packet ID to check + * @return True if we're expecting a reply + */ + inline bool expectingReplyTo(const uint64_t packetId) const + { + const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { + if (_expectingRepliesTo[bucket][i] == packetId) + return true; + } + return false; + } + private: inline SharedPtr _network(uint64_t nwid) const { @@ -266,6 +297,9 @@ private: void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P + uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; + uint64_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; + ZT_DataStoreGetFunction _dataStoreGetFunction; ZT_DataStorePutFunction _dataStorePutFunction; ZT_WirePacketSendFunction _wirePacketSendFunction; diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 33c28f65..6e811581 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -91,6 +91,7 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr2); + RR->node->expectReplyTo(_packet.packetId()); RR->sw->send(_packet,true); } } diff --git a/node/Packet.hpp b/node/Packet.hpp index 5ead2c3d..2ca73a84 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -965,7 +965,7 @@ public: * <[2] 16-bit reporter OS/platform or 0 if not specified> * <[2] 16-bit reporter architecture or 0 if not specified> * <[2] 16-bit error code (set to 0, currently unused)> - * <[8] 64-bit report flags (set to 0, currently unused)> + * <[8] 64-bit report flags> * <[8] 64-bit packet ID of received CIRCUIT_TEST packet> * <[5] upstream ZeroTier address from which CIRCUIT_TEST was received> * <[1] 8-bit packet hop count of received CIRCUIT_TEST> @@ -980,6 +980,9 @@ public: * <[5] ZeroTier address of next hop> * <[...] current best direct path address, if any, 0 if none> * + * Report flags: + * 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid) + * * Circuit test reports can be sent by hops in a circuit test to report * back results. They should include information about the sender as well * as about the paths to which next hops are being sent. diff --git a/node/Peer.cpp b/node/Peer.cpp index 58faab3b..a7a9fcc3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -266,6 +266,7 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u atAddress.serialize(outp); outp.append((uint64_t)RR->topology->worldId()); outp.append((uint64_t)RR->topology->worldTimestamp()); + RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } @@ -274,6 +275,7 @@ void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &at { if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); + RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { diff --git a/node/Switch.cpp b/node/Switch.cpp index 21d0b3c9..f2a0d35b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -734,13 +734,12 @@ unsigned long Switch::doTimerTasks(uint64_t now) Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { - SharedPtr root(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); - if (root) { - Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS); + SharedPtr upstream(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); + if (upstream) { + Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); - outp.armor(root->key(),true); - if (root->sendDirect(outp.data(),outp.size(),RR->node->now(),true)) - return root->address(); + RR->node->expectReplyTo(outp.packetId()); + send(outp,true); } return Address(); } -- cgit v1.2.3 From ab9afbc749f24f08f25dcf8bd6f4263b97c79bb9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Sep 2016 11:36:10 -0700 Subject: (1) Public networks now get COMs even though they do not gate with them since they will need them to push auth for multicast stuff, (2) added a bunch of rate limit circuit breakers for anti-DOS, (3) cleanup. --- controller/EmbeddedNetworkController.cpp | 12 +-- node/Constants.hpp | 20 ++++ node/IncomingPacket.cpp | 152 ++++++++++++++++++----------- node/IncomingPacket.hpp | 2 +- node/Membership.cpp | 2 +- node/Multicaster.cpp | 80 ++++++++++------ node/Multicaster.hpp | 40 ++++++++ node/Network.cpp | 72 ++++++++------ node/Network.hpp | 20 ++-- node/Node.cpp | 2 +- node/Path.hpp | 15 +++ node/Peer.cpp | 160 +++++++++++++++---------------- node/Peer.hpp | 43 ++++++++- 13 files changed, 393 insertions(+), 227 deletions(-) (limited to 'node/Peer.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 79560dcc..861792ed 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -924,13 +924,11 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest( } } - if (_jB(network["private"],true)) { - CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); - if (com.sign(signingId)) { - nc.com = com; - } else { - return NETCONF_QUERY_INTERNAL_SERVER_ERROR; - } + CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); + if (com.sign(signingId)) { + nc.com = com; + } else { + return NETCONF_QUERY_INTERNAL_SERVER_ERROR; } _writeJson(memberJP,member); diff --git a/node/Constants.hpp b/node/Constants.hpp index a625b480..05cd765a 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -236,6 +236,11 @@ */ #define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10) +/** + * Expiration for credentials presented for MULTICAST_LIKE or MULTICAST_GATHER (for non-network-members) + */ +#define ZT_MULTICAST_CREDENTIAL_EXPIRATON ZT_MULTICAST_LIKE_EXPIRE + /** * Timeout for outgoing multicasts * @@ -263,6 +268,11 @@ */ #define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 +/** + * Do not accept HELLOs over a given path more often than this + */ +#define ZT_PATH_HELLO_RATE_LIMIT 1000 + /** * Delay between full-fledge pings of directly connected peers */ @@ -283,6 +293,11 @@ */ #define ZT_PEER_ACTIVITY_TIMEOUT 500000 +/** + * General rate limit timeout for multiple packet types (HELLO, etc.) + */ +#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 1000 + /** * Delay between requests for updated network autoconf information * @@ -326,6 +341,11 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 +/** + * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound + */ +#define ZT_PEER_GENERAL_RATE_LIMIT 1000 + /** * Maximum number of direct path pushes within cutoff time * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1ce942c9..7f996dab 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -62,11 +62,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { - // A null pointer for peer to _doHELLO() tells it to run its own - // special internal authentication logic. This is done for unencrypted - // HELLOs to learn new identities, etc. - SharedPtr tmp; - return _doHELLO(RR,tmp); + // Only HELLO is allowed in the clear, but will still have a MAC + return _doHELLO(RR,false); } SharedPtr peer(RR->topology->getPeer(sourceAddress)); @@ -91,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,peer); + case Packet::VERB_HELLO: return _doHELLO(RR,true); case Packet::VERB_ERROR: return _doERROR(RR,peer); case Packet::VERB_OK: return _doOK(RR,peer); case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); @@ -192,16 +189,16 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr return true; } -bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer) +bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated) { - /* Note: this is the only packet ever sent in the clear, and it's also - * the only packet that we authenticate via a different path. Authentication - * occurs here and is based on the validity of the identity and the - * integrity of the packet's MAC, but it must be done after we check - * the identity since HELLO is a mechanism for learning new identities - * in the first place. */ - try { + const uint64_t now = RR->node->now(); + + if (!_path->rateGateHello(now)) { + TRACE("dropped HELLO from %s(%s): rate limiting circuit breaker for HELLO on this path tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + const uint64_t pid = packetId(); const Address fromAddress(source()); const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; @@ -228,20 +225,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } } - if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } if (fromAddress != id.address()) { TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; } + if (protoVersion < ZT_PROTO_VERSION_MIN) { + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } - if (!peer) { // peer == NULL is the normal case here - peer = RR->topology->getPeer(id.address()); - if (peer) { - // We already have an identity with this address -- check for collisions - + SharedPtr peer(RR->topology->getPeer(id.address())); + if (peer) { + // We already have an identity with this address -- check for collisions + if (!alreadyAuthenticated) { if (peer->identity() != id) { // Identity is different from the one we already have -- address collision @@ -273,31 +269,37 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer // Continue at // VALID } - } else { - // We don't already have an identity with this address -- validate and learn it + } // else continue at // VALID + } else { + // We don't already have an identity with this address -- validate and learn it - // Check identity proof of work - if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } + // Sanity check: this basically can't happen + if (alreadyAuthenticated) { + TRACE("dropped HELLO from %s(%s): somehow already authenticated with unknown peer?",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } - // Check packet integrity and authentication - SharedPtr newPeer(new Peer(RR,RR->identity,id)); - if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); - return true; - } - peer = RR->topology->addPeer(newPeer); + // Check identity proof of work + if (!id.locallyValidate()) { + TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; + } - // Continue at // VALID + // Check packet integrity and authentication + SharedPtr newPeer(new Peer(RR,RR->identity,id)); + if (!dearmor(newPeer->key())) { + TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; } + peer = RR->topology->addPeer(newPeer); - // VALID -- if we made it here, packet passed identity and authenticity checks! + // Continue at // VALID } + // VALID -- if we made it here, packet passed identity and authenticity checks! + if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now()); + RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_HELLO); @@ -349,7 +351,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer } outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); @@ -443,7 +445,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->gateMulticastGather(peer,verb(),packetId()))) { + if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -469,7 +471,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->addCredential(com); } - if (network->gateMulticastGather(peer,verb(),packetId())) { + if (network->gateMulticastGatherReply(peer,verb(),packetId())) { if ((flags & 0x02) != 0) { // OK(MULTICAST_FRAME) includes implicit gather results offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; @@ -494,6 +496,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { + if (!peer->rateGateInboundWhoisRequest(RR->node->now())) { + TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); outp.append(packetId()); @@ -672,6 +679,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&peer) { try { + if (!peer->rateGateEchoRequest(RR->node->now())) { + TRACE("dropped ECHO from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + const uint64_t pid = packetId(); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_ECHO); @@ -680,6 +692,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),RR->node->now()); + peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -692,11 +705,35 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared try { const uint64_t now = RR->node->now(); + uint64_t authOnNetwork[256]; + unsigned int authOnNetworkCount = 0; + SharedPtr network; + // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); - const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); - RR->mc->add(now,nwid,group,peer->address()); + + bool auth = false; + for(unsigned int i=0;iid() != nwid)) + network = RR->node->network(nwid); + if ( ((network)&&(network->gate(peer,verb(),packetId()))) || RR->mc->cacheAuthorized(peer->address(),nwid,now) ) { + auth = true; + if (authOnNetworkCount < 256) // sanity check, packets can't really be this big + authOnNetwork[authOnNetworkCount++] = nwid; + } + } + + if (auth) { + const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); + RR->mc->add(now,nwid,group,peer->address()); + } } peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); @@ -721,7 +758,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S if (network) { if (network->addCredential(com) == 1) return false; // wait for WHOIS - } + } else RR->mc->addCredential(com,false); } } ++p; // skip trailing 0 after COMs if present @@ -759,22 +796,21 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons { try { const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); - - const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); - const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); - const Dictionary metaData(metaDataBytes,metaDataLength); - const unsigned int hopCount = hops(); const uint64_t requestPacketId = packetId(); - bool netconfOk = false; + bool trustEstablished = false; if (RR->localNetworkController) { + const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN); + const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength); + const Dictionary metaData(metaDataBytes,metaDataLength); + NetworkConfig *netconf = new NetworkConfig(); try { switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) { case NetworkController::NETCONF_QUERY_OK: { - netconfOk = true; + trustEstablished = true; Dictionary *dconf = new Dictionary(); try { if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) { @@ -846,7 +882,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons _path->send(RR,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk); + peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,trustEstablished); } catch (std::exception &exc) { fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -897,21 +933,23 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); + const SharedPtr network(RR->node->network(nwid)); + if ((flags & 0x01) != 0) { try { CertificateOfMembership com; com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); if (com) { - SharedPtr network(RR->node->network(nwid)); if (network) network->addCredential(com); + else RR->mc->addCredential(com,false); } } catch ( ... ) { TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); } } - if (gatherLimit) { + if ( ( ((network)&&(network->gate(peer,verb(),packetId()))) || (RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now())) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); outp.append(packetId()); @@ -1043,7 +1081,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha const uint64_t now = RR->node->now(); // First, subject this to a rate limit - if (!peer->shouldRespondToDirectPathPush(now)) { + if (!peer->rateGatePushDirectPaths(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 35438f4f..dbaf67b8 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -136,7 +136,7 @@ private: // These are called internally to handle packet contents once it has // been authenticated, decrypted, decompressed, and classified. bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer); // can be called with NULL peer, while all others cannot + bool _doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated); bool _doOK(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer); diff --git a/node/Membership.cpp b/node/Membership.cpp index 4ca008e3..8c2ba673 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -71,7 +71,7 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint } capsAndTags.setAt(tagCountPos,(uint16_t)appendedTags); - const bool needCom = ((nconf.isPrivate())&&(nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)); + const bool needCom = ((nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)); if ( (needCom) || (appendedCaps) || (appendedTags) ) { Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); if (needCom) { diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 36d7d2d0..fc8fa1bd 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -34,8 +34,8 @@ namespace ZeroTier { Multicaster::Multicaster(const RuntimeEnvironment *renv) : RR(renv), - _groups(1024), - _groups_m() + _groups(256), + _gatherAuth(256) { } @@ -244,7 +244,7 @@ void Multicaster::send( } for(unsigned int k=0;kconfig())&&(network->config().isPrivate())) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; + const CertificateOfMembership *com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER); outp.append(nwid); outp.append((uint8_t)((com) ? 0x01 : 0x00)); @@ -301,42 +301,62 @@ void Multicaster::send( void Multicaster::clean(uint64_t now) { - Mutex::Lock _l(_groups_m); - - Multicaster::Key *k = (Multicaster::Key *)0; - MulticastGroupStatus *s = (MulticastGroupStatus *)0; - Hashtable::Iterator mm(_groups); - while (mm.next(k,s)) { - for(std::list::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { - if ((tx->expired(now))||(tx->atLimit())) - s->txQueue.erase(tx++); - else ++tx; - } + { + Mutex::Lock _l(_groups_m); + Multicaster::Key *k = (Multicaster::Key *)0; + MulticastGroupStatus *s = (MulticastGroupStatus *)0; + Hashtable::Iterator mm(_groups); + while (mm.next(k,s)) { + for(std::list::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { + if ((tx->expired(now))||(tx->atLimit())) + s->txQueue.erase(tx++); + else ++tx; + } - unsigned long count = 0; - { - std::vector::iterator reader(s->members.begin()); - std::vector::iterator writer(reader); - while (reader != s->members.end()) { - if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { - *writer = *reader; - ++writer; - ++count; + unsigned long count = 0; + { + std::vector::iterator reader(s->members.begin()); + std::vector::iterator writer(reader); + while (reader != s->members.end()) { + if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { + *writer = *reader; + ++writer; + ++count; + } + ++reader; } - ++reader; + } + + if (count) { + s->members.resize(count); + } else if (s->txQueue.empty()) { + _groups.erase(*k); + } else { + s->members.clear(); } } + } - if (count) { - s->members.resize(count); - } else if (s->txQueue.empty()) { - _groups.erase(*k); - } else { - s->members.clear(); + { + Mutex::Lock _l(_gatherAuth_m); + _GatherAuthKey *k = (_GatherAuthKey *)0; + uint64_t *ts = (uint64_t *)ts; + Hashtable<_GatherAuthKey,uint64_t>::Iterator i(_gatherAuth); + while (i.next(k,ts)) { + if ((now - *ts) >= ZT_MULTICAST_CREDENTIAL_EXPIRATON) + _gatherAuth.erase(*k); } } } +void Multicaster::addCredential(const CertificateOfMembership &com,bool alreadyValidated) +{ + if ((alreadyValidated)||(com.verify(RR) == 0)) { + Mutex::Lock _l(_gatherAuth_m); + _gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now(); + } +} + void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) { // assumes _groups_m is locked diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 51dabc69..8be3b736 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -179,12 +179,52 @@ public: */ void clean(uint64_t now); + /** + * Add an authorization credential + * + * The Multicaster keeps its own track of when valid credentials of network + * membership are presented. This allows it to control MULTICAST_LIKE + * GATHER authorization for networks this node does not belong to. + * + * @param com Certificate of membership + * @param alreadyValidated If true, COM has already been checked and found to be valid and signed + */ + void addCredential(const CertificateOfMembership &com,bool alreadyValidated); + + /** + * Check authorization for GATHER and LIKE for non-network-members + * + * @param a Address of peer + * @param nwid Network ID + * @param now Current time + * @return True if GATHER and LIKE should be allowed + */ + bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const + { + Mutex::Lock _l(_gatherAuth_m); + const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a)); + return ((p)&&((now - *p) < ZT_MULTICAST_CREDENTIAL_EXPIRATON)); + } + private: void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); const RuntimeEnvironment *RR; + Hashtable _groups; Mutex _groups_m; + + struct _GatherAuthKey + { + _GatherAuthKey() : member(0),networkId(0) {} + _GatherAuthKey(const uint64_t nwid,const Address &a) : member(a.toInt()),networkId(nwid) {} + inline unsigned long hashCode() const { return (member ^ networkId); } + inline bool operator==(const _GatherAuthKey &k) const { return ((member == k.member)&&(networkId == k.networkId)); } + uint64_t member; + uint64_t networkId; + }; + Hashtable< _GatherAuthKey,uint64_t > _gatherAuth; + Mutex _gatherAuth_m; }; } // namespace ZeroTier diff --git a/node/Network.cpp b/node/Network.cpp index a9b14942..146f2962 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -866,31 +866,24 @@ bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBr return true; else if (includeBridgedGroups) return _multicastGroupsBehindMe.contains(mg); - else return false; + return false; } void Network::multicastSubscribe(const MulticastGroup &mg) { - { - Mutex::Lock _l(_lock); - if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) - return; - _myMulticastGroups.push_back(mg); - std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end()); - _pushStateToMembers(&mg); + Mutex::Lock _l(_lock); + if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { + _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg); + _sendUpdatesToMembers(&mg); } } void Network::multicastUnsubscribe(const MulticastGroup &mg) { Mutex::Lock _l(_lock); - std::vector nmg; - for(std::vector::const_iterator i(_myMulticastGroups.begin());i!=_myMulticastGroups.end();++i) { - if (*i != mg) - nmg.push_back(*i); - } - if (nmg.size() != _myMulticastGroups.size()) - _myMulticastGroups.swap(nmg); + std::vector::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)); + if ( (i != _myMulticastGroups.end()) && (*i == mg) ) + _myMulticastGroups.erase(i); } bool Network::applyConfiguration(const NetworkConfig &conf) @@ -1054,30 +1047,29 @@ void Network::requestConfiguration() } else { outp.append((unsigned char)0,16); } - RR->node->expectReplyTo(outp.packetId()); - outp.compress(); - RR->sw->send(outp,true); - // Expect replies with this in-re packet ID - _inboundConfigPacketId = outp.packetId(); + RR->node->expectReplyTo(_inboundConfigPacketId = outp.packetId()); _inboundConfigChunks.clear(); + + outp.compress(); + RR->sw->send(outp,true); } bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) { + const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); try { if (_config) { Membership &m = _membership(peer->address()); const bool allow = m.isAllowedOnNetwork(_config); if (allow) { - const uint64_t now = RR->node->now(); m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); if (m.shouldLikeMulticasts(now)) { _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); m.likingMulticasts(now); } - } else if (m.recentlyAllowedOnNetwork(_config)) { + } else if (m.recentlyAllowedOnNetwork(_config)&&peer->rateGateRequestCredentials(now)) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)verb); outp.append(packetId); @@ -1093,7 +1085,7 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } -bool Network::gateMulticastGather(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) { return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); } @@ -1180,7 +1172,22 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _pushStateToMembers(&mg); + _sendUpdatesToMembers(&mg); +} + +int Network::addCredential(const CertificateOfMembership &com) +{ + if (com.networkId() != _id) + return -1; + const Address a(com.issuedTo()); + Mutex::Lock _l(_lock); + Membership &m = _membership(a); + const int result = m.addCredential(RR,com); + if (result == 0) { + m.sendCredentialsIfNeeded(RR,RR->node->now(),a,_config,(const Capability *)0); + RR->mc->addCredential(com,true); + } + return result; } void Network::destroy() @@ -1245,7 +1252,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } } -void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) +void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked const uint64_t now = RR->node->now(); @@ -1263,7 +1270,7 @@ void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) // them our COM so that MULTICAST_GATHER can be authenticated properly. const std::vector

upstreams(RR->topology->upstreamAddresses()); for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { - if ((_config.isPrivate())&&(_config.com)) { + if (_config.com) { Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); _config.com.serialize(outp); outp.append((uint8_t)0x00); @@ -1272,12 +1279,17 @@ void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup) _announceMulticastGroupsTo(*a,groups); } - // Announce to controller, which does not need our COM since it obviously - // knows if we are a member. Of course if we already did or are going to - // below then we can skip it here. + // Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it const Address c(controller()); - if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) ) + if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) ) { + if (_config.com) { + Packet outp(c,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + _config.com.serialize(outp); + outp.append((uint8_t)0x00); + RR->sw->send(outp,true); + } _announceMulticastGroupsTo(c,groups); + } } // Make sure that all "network anchors" have Membership records so we will diff --git a/node/Network.hpp b/node/Network.hpp index d80b13b9..7a4065ff 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -260,7 +260,7 @@ public: /** * Check whether this peer is allowed to provide multicast info for this network */ - bool gateMulticastGather(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); /** * @param peer Peer to check @@ -276,10 +276,10 @@ public: /** * Push state to members such as multicast group memberships and latest COM (if needed) */ - inline void pushStateToMembers() + inline void sendUpdatesToMembers() { Mutex::Lock _l(_lock); - _pushStateToMembers((const MulticastGroup *)0); + _sendUpdatesToMembers((const MulticastGroup *)0); } /** @@ -332,9 +332,7 @@ public: { Mutex::Lock _l(_lock); const Address *const br = _remoteBridgeRoutes.get(mac); - if (br) - return *br; - return Address(); + return ((br) ? *br : Address()); } /** @@ -357,13 +355,7 @@ public: * @param com Certificate of membership * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - inline int addCredential(const CertificateOfMembership &com) - { - if (com.networkId() != _id) - return -1; - Mutex::Lock _l(_lock); - return _membership(com.issuedTo()).addCredential(RR,com); - } + int addCredential(const CertificateOfMembership &com); /** * @param cap Capability @@ -418,7 +410,7 @@ private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _gate(const SharedPtr &peer); - void _pushStateToMembers(const MulticastGroup *const newMulticastGroup); + void _sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup); void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; Membership &_membership(const Address &a); diff --git a/node/Node.cpp b/node/Node.cpp index e8279c62..59794854 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -266,7 +266,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - n->second->pushStateToMembers(); + n->second->sendUpdatesToMembers(); } } for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) diff --git a/node/Path.hpp b/node/Path.hpp index 27cff645..6278532d 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -104,6 +104,7 @@ public: Path() : _lastOut(0), _lastIn(0), + _lastHello(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -113,6 +114,7 @@ public: Path(const InetAddress &localAddress,const InetAddress &addr) : _lastOut(0), _lastIn(0), + _lastHello(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -229,9 +231,22 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } + /** + * @return True if we should allow HELLO via this path + */ + inline bool rateGateHello(const uint64_t now) + { + if ((now - _lastHello) >= ZT_PATH_HELLO_RATE_LIMIT) { + _lastHello = now; + return true; + } + return false; + } + private: uint64_t _lastOut; uint64_t _lastIn; + uint64_t _lastHello; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index a7a9fcc3..0e6ef333 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -47,6 +47,9 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastMulticastFrame(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), + _lastCredentialRequestSent(0), + _lastWhoisRequestReceived(0), + _lastEchoRequestReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), @@ -194,7 +197,80 @@ void Peer::received( } } else if (trustEstablished) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) - _pushDirectPaths(path,now); +#ifdef ZT_ENABLE_CLUSTER + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + const bool haveCluster = (RR->cluster); +#else + const bool haveCluster = false; +#endif + if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { + _lastDirectPathPushSent = now; + + std::vector pathsToPush; + + std::vector dps(RR->node->directPaths()); + for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) + pathsToPush.push_back(*i); + + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } + } + + if (pathsToPush.size() > 0) { +#ifdef ZT_TRACE + std::string ps; + for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { + if (ps.length() > 0) + ps.push_back(','); + ps.append(p->toString()); + } + TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); +#endif + + std::vector::const_iterator p(pathsToPush.begin()); + while (p != pathsToPush.end()) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); + outp.addSize(2); // leave room for count + + unsigned int count = 0; + while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { + uint8_t addressType = 4; + switch(p->ss_family) { + case AF_INET: + break; + case AF_INET6: + addressType = 6; + break; + default: // we currently only push IP addresses + ++p; + continue; + } + + outp.append((uint8_t)0); // no flags + outp.append((uint16_t)0); // no extensions + outp.append(addressType); + outp.append((uint8_t)((addressType == 4) ? 6 : 18)); + outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); + outp.append((uint16_t)p->port()); + + ++count; + ++p; + } + + if (count) { + outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); + outp.armor(_key,true); + path->send(RR,outp.data(),outp.size(),now); + } + } + } + } } } @@ -368,86 +444,4 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) v6 = _paths[bestp6].path->address(); } -bool Peer::_pushDirectPaths(const SharedPtr &path,uint64_t now) -{ -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - if (RR->cluster) - return false; -#endif - - if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL) - return false; - else _lastDirectPathPushSent = now; - - std::vector pathsToPush; - - std::vector dps(RR->node->directPaths()); - for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) - pathsToPush.push_back(*i); - - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; - } - } - if (pathsToPush.empty()) - return false; - -#ifdef ZT_TRACE - { - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); - } -#endif - - std::vector::const_iterator p(pathsToPush.begin()); - while (p != pathsToPush.end()) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.addSize(2); // leave room for count - - unsigned int count = 0; - while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) { - uint8_t addressType = 4; - switch(p->ss_family) { - case AF_INET: - break; - case AF_INET6: - addressType = 6; - break; - default: // we currently only push IP addresses - ++p; - continue; - } - - outp.append((uint8_t)0); // no flags - outp.append((uint16_t)0); // no extensions - outp.append(addressType); - outp.append((uint8_t)((addressType == 4) ? 6 : 18)); - outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16)); - outp.append((uint16_t)p->port()); - - ++count; - ++p; - } - - if (count) { - outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true); - path->send(RR,outp.data(),outp.size(),now); - } - } - - return true; -} - } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 2e64fb4d..d714b937 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -348,7 +348,7 @@ public: * @param now Current time * @return True if we should respond */ - inline bool shouldRespondToDirectPathPush(const uint64_t now) + inline bool rateGatePushDirectPaths(const uint64_t now) { if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) ++_directPathPushCutoffCount; @@ -357,6 +357,42 @@ public: return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); } + /** + * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE + */ + inline bool rateGateRequestCredentials(const uint64_t now) + { + if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastCredentialRequestSent = now; + return true; + } + return false; + } + + /** + * Rate limit gate for inbound WHOIS requests + */ + inline bool rateGateInboundWhoisRequest(const uint64_t now) + { + if ((now - _lastWhoisRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastWhoisRequestReceived = now; + return true; + } + return false; + } + + /** + * Rate limit gate for inbound ECHO requests + */ + inline bool rateGateEchoRequest(const uint64_t now) + { + if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastEchoRequestReceived = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -378,8 +414,6 @@ public: } private: - bool _pushDirectPaths(const SharedPtr &path,uint64_t now); - inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const { uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); @@ -415,6 +449,9 @@ private: uint64_t _lastMulticastFrame; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; + uint64_t _lastCredentialRequestSent; + uint64_t _lastWhoisRequestReceived; + uint64_t _lastEchoRequestReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; -- cgit v1.2.3 From ea1da3321a8f95eb2f42b62d805841e2d8379e21 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 12 Sep 2016 15:19:21 -0700 Subject: Rate gate requests for COM. --- node/IncomingPacket.cpp | 13 ++++++++----- node/Peer.cpp | 1 + node/Peer.hpp | 13 +++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a1458a80..eff87350 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -156,11 +156,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - network->config().com.serialize(outp); - outp.append((uint8_t)0); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + const uint64_t now = RR->node->now(); + if (peer->rateGateComRequest(now)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + network->config().com.serialize(outp); + outp.append((uint8_t)0); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),now); + } } } break; diff --git a/node/Peer.cpp b/node/Peer.cpp index 0e6ef333..f7a21ab1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -50,6 +50,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastCredentialRequestSent(0), _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), + _lastComRequestReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), diff --git a/node/Peer.hpp b/node/Peer.hpp index d714b937..a804dd91 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -393,6 +393,18 @@ public: return false; } + /** + * Rate gate requests for network COM + */ + inline bool rateGateComRequest(const uint64_t now) + { + if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastComRequestReceived = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -452,6 +464,7 @@ private: uint64_t _lastCredentialRequestSent; uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; + uint64_t _lastComRequestReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; -- cgit v1.2.3 From cba37c610786417ad73f455cfb3b6c5d0daf07e8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Sep 2016 10:13:23 -0700 Subject: Add a few more rate limit gates for anti-DOS hardening. --- node/Constants.hpp | 20 +++++++++++++----- node/IncomingPacket.cpp | 54 ++++++++++++++++++++++++++++++++++++++++--------- node/Peer.cpp | 4 +++- node/Peer.hpp | 24 +++++++++++++--------- 4 files changed, 77 insertions(+), 25 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 05cd765a..afd2e4ec 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -341,11 +341,6 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 -/** - * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound - */ -#define ZT_PEER_GENERAL_RATE_LIMIT 1000 - /** * Maximum number of direct path pushes within cutoff time * @@ -355,6 +350,21 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 +/** + * Time horizon for VERB_NETWORK_CREDENTIALS cutoff + */ +#define ZT_PEER_CREDENTIALS_CUTOFF_TIME 60000 + +/** + * Maximum number of VERB_NETWORK_CREDENTIALS within cutoff time + */ +#define ZT_PEER_CREDEITIALS_CUTOFF_LIMIT 15 + +/** + * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound + */ +#define ZT_PEER_GENERAL_RATE_LIMIT 1000 + /** * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index eff87350..84503406 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -133,6 +133,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr switch(errorCode) { case Packet::ERROR_OBJ_NOT_FOUND: + // Object not found, currently only meaningful from network controllers. if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) @@ -141,6 +142,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_UNSUPPORTED_OPERATION: + // This can be sent in response to any operation, though right now we only + // consider it meaningful from network controllers. This would indicate + // that the queried node does not support acting as a controller. if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) @@ -149,11 +153,18 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_IDENTITY_COLLISION: + // Roots are the only peers currently permitted to state authoritatively + // that an identity has collided. When this occurs the node should be shut + // down and a new identity created. The odds of this ever happening are + // very low. if (RR->topology->isRoot(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + // This error can be sent in response to any packet that fails network + // authorization. We only listen to it if it's from a peer that has recently + // been authorized on this network. SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { const uint64_t now = RR->node->now(); @@ -168,12 +179,15 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr } break; case Packet::ERROR_NETWORK_ACCESS_DENIED_: { + // Network controller: network access denied. SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->controller() == peer->address())) network->setAccessDenied(); } break; case Packet::ERROR_UNWANTED_MULTICAST: { + // Members of networks can use this error to indicate that they no longer + // want to receive multicasts on a given channel. SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->gate(peer,verb(),packetId()))) { MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); @@ -301,6 +315,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // VALID -- if we made it here, packet passed identity and authenticity checks! + // Learn our external surface address from other peers to help us negotiate symmetric NATs + // and detect changes to our global IP that can trigger path renegotiation. if ((externalSurfaceAddress)&&(hops() == 0)) RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); @@ -370,6 +386,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + // Don't parse OK packets that are not in response to a packet ID we sent if (!RR->node->expectingReplyTo(inRePacketId)) { TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); return true; @@ -711,6 +728,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared uint64_t authOnNetwork[256]; unsigned int authOnNetworkCount = 0; SharedPtr network; + bool trustEstablished = false; // Iterate through 18-byte network,MAC,ADI tuples for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptrid() != nwid)) network = RR->node->network(nwid); - if ( ((network)&&(network->gate(peer,verb(),packetId()))) || RR->mc->cacheAuthorized(peer->address(),nwid,now) ) { + const bool authOnNet = ((network)&&(network->gate(peer,verb(),packetId()))); + trustEstablished |= authOnNet; + if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; if (authOnNetworkCount < 256) // sanity check, packets can't really be this big authOnNetwork[authOnNetworkCount++] = nwid; @@ -739,7 +759,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -749,9 +769,15 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { + if (!peer->rateGateCredentialsReceived(RR->node->now())) { + TRACE("dropped NETWORK_CREDENTIALS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + return true; + } + CertificateOfMembership com; Capability cap; Tag tag; + bool trustEstablished = false; unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p])) { @@ -759,8 +785,10 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S if (com) { SharedPtr network(RR->node->network(com.networkId())); if (network) { - if (network->addCredential(com) == 1) - return false; // wait for WHOIS + switch (network->addCredential(com)) { + case 0: trustEstablished = true; break; + case 1: return false; // wait for WHOIS + } } else RR->mc->addCredential(com,false); } } @@ -772,8 +800,10 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += cap.deserialize(*this,p); SharedPtr network(RR->node->network(cap.networkId())); if (network) { - if (network->addCredential(cap) == 1) - return false; // wait for WHOIS + switch (network->addCredential(cap)) { + case 0: trustEstablished = true; break; + case 1: return false; // wait for WHOIS + } } } @@ -782,13 +812,15 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += tag.deserialize(*this,p); SharedPtr network(RR->node->network(tag.networkId())); if (network) { - if (network->addCredential(tag) == 1) - return false; // wait for WHOIS + switch (network->addCredential(tag)) { + case 0: trustEstablished = true; break; + case 1: return false; // wait for WHOIS + } } } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -900,11 +932,13 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons { try { const uint64_t nwid = at(ZT_PACKET_IDX_PAYLOAD); + bool trustEstablished = false; if (Network::controllerFor(nwid) == peer->address()) { SharedPtr network(RR->node->network(nwid)); if (network) { network->requestConfiguration(); + trustEstablished = true; } else { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): not a member of %.16llx",source().toString().c_str(),_path->address().toString().c_str(),nwid); peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); @@ -919,7 +953,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,false); + peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } diff --git a/node/Peer.cpp b/node/Peer.cpp index f7a21ab1..560ca786 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -51,6 +51,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), _lastComRequestReceived(0), + _lastCredentialsReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), @@ -60,7 +61,8 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _id(peerIdentity), _numPaths(0), _latency(0), - _directPathPushCutoffCount(0) + _directPathPushCutoffCount(0), + _credentialsCutoffCount(0) { memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) diff --git a/node/Peer.hpp b/node/Peer.hpp index a804dd91..5382e3f0 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -338,15 +338,7 @@ public: inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } /** - * Update direct path push stats and return true if we should respond - * - * This is a circuit breaker to make VERB_PUSH_DIRECT_PATHS not particularly - * useful as a DDOS amplification attack vector. Otherwise a malicious peer - * could send loads of these and cause others to bombard arbitrary IPs with - * traffic. - * - * @param now Current time - * @return True if we should respond + * Rate limit gate for VERB_PUSH_DIRECT_PATHS */ inline bool rateGatePushDirectPaths(const uint64_t now) { @@ -357,6 +349,18 @@ public: return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); } + /** + * Rate limit gate for VERB_NETWORK_CREDENTIALS + */ + inline bool rateGateCredentialsReceived(const uint64_t now) + { + if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME) + ++_credentialsCutoffCount; + else _credentialsCutoffCount = 0; + _lastCredentialsReceived = now; + return (_directPathPushCutoffCount < ZT_PEER_CREDEITIALS_CUTOFF_LIMIT); + } + /** * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE */ @@ -465,6 +469,7 @@ private: uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; + uint64_t _lastCredentialsReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; @@ -483,6 +488,7 @@ private: unsigned int _numPaths; unsigned int _latency; unsigned int _directPathPushCutoffCount; + unsigned int _credentialsCutoffCount; AtomicCounter __refCount; }; -- cgit v1.2.3 From 5b6d27e65919cf0429feb2d8a9ce0b6164153efd Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Sep 2016 14:27:18 -0700 Subject: Implement relay policy, and setting multicast limit to 0 now disables multicast on the network as would be expected. --- include/ZeroTierOne.h | 38 ++++++++++++++++++----- node/Constants.hpp | 9 ++++-- node/IncomingPacket.cpp | 16 ++++++++-- node/Node.cpp | 22 ++++++++++++- node/Node.hpp | 3 ++ node/Path.hpp | 13 ++++++++ node/Peer.cpp | 6 ++++ node/Peer.hpp | 18 +++++++---- node/Switch.cpp | 31 +++++++++++++++++-- osdep/ManagedRoute.cpp | 80 +++++++++++++----------------------------------- osdep/ManagedRoute.hpp | 4 +-- service/ControlPlane.cpp | 2 +- 12 files changed, 159 insertions(+), 83 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 633db7cf..e4ea92b4 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -870,19 +870,28 @@ enum ZT_VirtualNetworkConfigOperation ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; +enum ZT_RelayPolicy +{ + ZT_RELAY_POLICY_NEVER = 0, + ZT_RELAY_POLICY_TRUSTED = 1, + ZT_RELAY_POLICY_ALWAYS = 2 +}; + /** * What trust hierarchy role does this peer have? */ -enum ZT_PeerRole { +enum ZT_PeerRole +{ ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_RELAY = 1, // relay node - ZT_PEER_ROLE_ROOT = 2 // root server + ZT_PEER_ROLE_UPSTREAM = 1, // upstream node + ZT_PEER_ROLE_ROOT = 2 // global root }; /** * Vendor ID */ -enum ZT_Vendor { +enum ZT_Vendor +{ ZT_VENDOR_UNSPECIFIED = 0, ZT_VENDOR_ZEROTIER = 1 }; @@ -890,7 +899,8 @@ enum ZT_Vendor { /** * Platform type */ -enum ZT_Platform { +enum ZT_Platform +{ ZT_PLATFORM_UNSPECIFIED = 0, ZT_PLATFORM_LINUX = 1, ZT_PLATFORM_WINDOWS = 2, @@ -905,13 +915,15 @@ enum ZT_Platform { ZT_PLATFORM_VXWORKS = 11, ZT_PLATFORM_FREERTOS = 12, ZT_PLATFORM_SYSBIOS = 13, - ZT_PLATFORM_HURD = 14 + ZT_PLATFORM_HURD = 14, + ZT_PLATFORM_WEB = 15 }; /** * Architecture type */ -enum ZT_Architecture { +enum ZT_Architecture +{ ZT_ARCHITECTURE_UNSPECIFIED = 0, ZT_ARCHITECTURE_X86 = 1, ZT_ARCHITECTURE_X64 = 2, @@ -926,7 +938,8 @@ enum ZT_Architecture { ZT_ARCHITECTURE_SPARC32 = 11, ZT_ARCHITECTURE_SPARC64 = 12, ZT_ARCHITECTURE_DOTNET_CLR = 13, - ZT_ARCHITECTURE_JAVA_JVM = 14 + ZT_ARCHITECTURE_JAVA_JVM = 14, + ZT_ARCHITECTURE_WEB = 15 }; /** @@ -1681,6 +1694,15 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( */ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); +/** + * Set node's relay policy + * + * @param node Node instance + * @param rp New relay policy + * @return OK(0) or error code + */ +enum ZT_ResultCode ZT_Node_setRelayPolicy(ZT_Node *node,enum ZT_RelayPolicy rp); + /** * Join a network * diff --git a/node/Constants.hpp b/node/Constants.hpp index afd2e4ec..b3c3dec0 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -350,6 +350,11 @@ */ #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 +/** + * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) + */ +#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 + /** * Time horizon for VERB_NETWORK_CREDENTIALS cutoff */ @@ -366,9 +371,9 @@ #define ZT_PEER_GENERAL_RATE_LIMIT 1000 /** - * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) + * How long is a path or peer considered to have a trust relationship with us (for e.g. relay policy) since last trusted established packet? */ -#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 +#define ZT_TRUST_EXPIRATION 600000 /** * Enable support for older network configurations from older (pre-1.1.6) controllers diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 64dccef3..9bc41d47 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -670,8 +670,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } - } else if ( (to != network->mac()) && (!to.isMulticast()) ) { - if (!network->config().permitsBridging(RR->identity.address())) { + } else if (to != network->mac()) { + if (to.isMulticast()) { + if (network->config().multicastLimit == 0) { + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + return true; + } + } else if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; @@ -1038,6 +1044,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share return true; } + if (network->config().multicastLimit == 0) { + TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + return true; + } + unsigned int gatherLimit = 0; if ((flags & 0x02) != 0) { gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); diff --git a/node/Node.cpp b/node/Node.cpp index 59794854..51f1b5c0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -71,7 +71,8 @@ Node::Node( _prngStreamPtr(0), _now(now), _lastPingCheck(0), - _lastHousekeepingRun(0) + _lastHousekeepingRun(0), + _relayPolicy(ZT_RELAY_POLICY_TRUSTED) { _online = false; @@ -118,6 +119,9 @@ Node::Node( throw; } + if (RR->topology->amRoot()) + _relayPolicy = ZT_RELAY_POLICY_ALWAYS; + postEvent(ZT_EVENT_UP); } @@ -131,6 +135,7 @@ Node::~Node() delete RR->topology; delete RR->mc; delete RR->sw; + #ifdef ZT_ENABLE_CLUSTER delete RR->cluster; #endif @@ -319,6 +324,12 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB return ZT_RESULT_OK; } +ZT_ResultCode Node::setRelayPolicy(enum ZT_RelayPolicy rp) +{ + _relayPolicy = rp; + return ZT_RESULT_OK; +} + ZT_ResultCode Node::join(uint64_t nwid,void *uptr) { Mutex::Lock _l(_networks_m); @@ -824,6 +835,15 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol } } +enum ZT_ResultCode ZT_Node_setRelayPolicy(ZT_Node *node,enum ZT_RelayPolicy rp) +{ + try { + return reinterpret_cast(node)->setRelayPolicy(rp); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr) { try { diff --git a/node/Node.hpp b/node/Node.hpp index 315b5248..56869816 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -91,6 +91,7 @@ public: unsigned int frameLength, volatile uint64_t *nextBackgroundTaskDeadline); ZT_ResultCode processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); + ZT_ResultCode setRelayPolicy(enum ZT_RelayPolicy rp); ZT_ResultCode join(uint64_t nwid,void *uptr); ZT_ResultCode leave(uint64_t nwid,void **uptr); ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); @@ -245,6 +246,7 @@ public: inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } inline bool online() const throw() { return _online; } + inline ZT_RelayPolicy relayPolicy() const { return _relayPolicy; } #ifdef ZT_TRACE void postTrace(const char *module,unsigned int line,const char *fmt,...); @@ -326,6 +328,7 @@ private: uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; + ZT_RelayPolicy _relayPolicy; bool _online; }; diff --git a/node/Path.hpp b/node/Path.hpp index 27cff645..5993be69 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -104,6 +104,7 @@ public: Path() : _lastOut(0), _lastIn(0), + _lastTrustEstablishedPacketReceived(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -113,6 +114,7 @@ public: Path(const InetAddress &localAddress,const InetAddress &addr) : _lastOut(0), _lastIn(0), + _lastTrustEstablishedPacketReceived(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -126,6 +128,11 @@ public: */ inline void received(const uint64_t t) { _lastIn = t; } + /** + * Set time last trusted packet was received (done in Peer::received()) + */ + inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; } + /** * Send a packet via this path (last out time is also updated) * @@ -159,6 +166,11 @@ public: */ inline InetAddress::IpScope ipScope() const { return _ipScope; } + /** + * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms + */ + inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + /** * @return Preference rank, higher == better */ @@ -232,6 +244,7 @@ public: private: uint64_t _lastOut; uint64_t _lastIn; + uint64_t _lastTrustEstablishedPacketReceived; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index 560ca786..78af9063 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -52,6 +52,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastEchoRequestReceived(0), _lastComRequestReceived(0), _lastCredentialsReceived(0), + _lastTrustEstablishedPacketReceived(0), RR(renv), _remoteClusterOptimal4(0), _vProto(0), @@ -132,6 +133,11 @@ void Peer::received( else if (verb == Packet::VERB_MULTICAST_FRAME) _lastMulticastFrame = now; + if (trustEstablished) { + _lastTrustEstablishedPacketReceived = now; + path->trustedPacketReceived(now); + } + if (hops == 0) { bool pathIsConfirmed = false; { diff --git a/node/Peer.hpp b/node/Peer.hpp index 5382e3f0..1ae239bc 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -312,7 +312,7 @@ public: /** * @return 256-bit secret symmetric encryption key */ - inline const unsigned char *key() const throw() { return _key; } + inline const unsigned char *key() const { return _key; } /** * Set the currently known remote version of this peer's client @@ -330,12 +330,17 @@ public: _vRevision = (uint16_t)vrev; } - inline unsigned int remoteVersionProtocol() const throw() { return _vProto; } - inline unsigned int remoteVersionMajor() const throw() { return _vMajor; } - inline unsigned int remoteVersionMinor() const throw() { return _vMinor; } - inline unsigned int remoteVersionRevision() const throw() { return _vRevision; } + inline unsigned int remoteVersionProtocol() const { return _vProto; } + inline unsigned int remoteVersionMajor() const { return _vMajor; } + inline unsigned int remoteVersionMinor() const { return _vMinor; } + inline unsigned int remoteVersionRevision() const { return _vRevision; } - inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } + inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } + + /** + * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms + */ + inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } /** * Rate limit gate for VERB_PUSH_DIRECT_PATHS @@ -470,6 +475,7 @@ private: uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; uint64_t _lastCredentialsReceived; + uint64_t _lastTrustEstablishedPacketReceived; const RuntimeEnvironment *RR; uint32_t _remoteClusterOptimal4; uint16_t _vProto; diff --git a/node/Switch.cpp b/node/Switch.cpp index ea92c99a..beb36b6c 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -105,7 +105,18 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from const Address destination(fragment.destination()); if (destination != RR->identity.address()) { - // Fragment is not for us, so try to relay it + switch(RR->node->relayPolicy()) { + case ZT_RELAY_POLICY_ALWAYS: + break; + case ZT_RELAY_POLICY_TRUSTED: + if (!path->trustEstablished(now)) + return; + break; + // case ZT_RELAY_POLICY_NEVER: + default: + return; + } + if (fragment.hops() < ZT_RELAY_MAX_HOPS) { fragment.incrementHops(); @@ -203,9 +214,20 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); if (destination != RR->identity.address()) { + switch(RR->node->relayPolicy()) { + case ZT_RELAY_POLICY_ALWAYS: + break; + case ZT_RELAY_POLICY_TRUSTED: + if (!path->trustEstablished(now)) + return; + break; + // case ZT_RELAY_POLICY_NEVER: + default: + return; + } + Packet packet(data,len); - // Packet is not for us, so try to relay it if (packet.hops() < ZT_RELAY_MAX_HOPS) { packet.incrementHops(); @@ -327,6 +349,11 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } if (to.isMulticast()) { + if (network->config().multicastLimit == 0) { + TRACE("%.16llx: dropped multicast: not allowed on network",network->id()); + return; + } + // Destination is a multicast address (including broadcast) MulticastGroup mg(to,0); diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 711a09ed..ae20bb34 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -436,12 +436,12 @@ bool ManagedRoute::sync() } if (!_applied.count(leftt)) { - _applied.insert(leftt); + _applied[rightt] = false; // not ifscoped _routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); _routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); } if ((rightt)&&(!_applied.count(rightt))) { - _applied.insert(rightt); + _applied[rightt] = false; // not ifscoped _routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); _routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device); } @@ -457,7 +457,7 @@ bool ManagedRoute::sync() } } else { if (!_applied.count(_target)) { - _applied.insert(_target); + _applied[_target] = true; // ifscoped _routeCmd("add",_target,_via,_device,(_via) ? (const char *)0 : _device); _routeCmd("change",_target,_via,_device,(_via) ? (const char *)0 : _device); } @@ -468,65 +468,27 @@ bool ManagedRoute::sync() #ifdef __LINUX__ // ---------------------------------------------------------- - //if (needBifurcation) { - if (!_applied.count(leftt)) { - _applied.insert(leftt); - _routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied.insert(rightt); - _routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device); - } - /*if (_applied.count(_target)) { - _applied.erase(_target); - _routeCmd("del",_target,_via,(_via) ? (const char *)0 : _device); - }*/ - /*} else { - if (_applied.count(leftt)) { - _applied.erase(leftt); - _routeCmd("del",leftt,_via,(_via) ? (const char *)0 : _device); - } - if ((rightt)&&(_applied.count(rightt))) { - _applied.erase(rightt); - _routeCmd("del",rightt,_via,(_via) ? (const char *)0 : _device); - } - if (!_applied.count(_target)) { - _applied.insert(_target); - _routeCmd("replace",_target,_via,(_via) ? (const char *)0 : _device); - } - }*/ + if (!_applied.count(leftt)) { + _applied[leftt] = false; // boolean unused + _routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device); + } + if ((rightt)&&(!_applied.count(rightt))) { + _applied[rightt] = false; // boolean unused + _routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device); + } #endif // __LINUX__ ---------------------------------------------------------- #ifdef __WINDOWS__ // -------------------------------------------------------- - //if (needBifurcation) { - if (!_applied.count(leftt)) { - _applied.insert(leftt); - _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); - } - if ((rightt)&&(!_applied.count(rightt))) { - _applied.insert(rightt); - _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); - } - /*if (_applied.count(_target)) { - _applied.erase(_target); - _winRoute(true,interfaceLuid,interfaceIndex,_target,_via); - }*/ - /*} else { - if (_applied.count(leftt)) { - _applied.erase(leftt); - _winRoute(true,interfaceLuid,interfaceIndex,leftt,_via); - } - if ((rightt)&&(_applied.count(rightt))) { - _applied.erase(rightt); - _winRoute(true,interfaceLuid,interfaceIndex,rightt,_via); - } - if (!_applied.count(_target)) { - _applied.insert(_target); - _winRoute(false,interfaceLuid,interfaceIndex,_target,_via); - } - }*/ + if (!_applied.count(leftt)) { + _applied[leftt] = false; // boolean unused + _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); + } + if ((rightt)&&(!_applied.count(rightt))) { + _applied[rightt] = false; // boolean unused + _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); + } #endif // __WINDOWS__ -------------------------------------------------------- @@ -553,9 +515,9 @@ void ManagedRoute::remove() } #endif // __BSD__ ------------------------------------------------------------ - for(std::set::iterator r(_applied.begin());r!=_applied.end();++r) { + for(std::map::iterator r(_applied.begin());r!=_applied.end();++r) { #ifdef __BSD__ // ------------------------------------------------------------ - _routeCmd("delete",*r,_via,(const char *)0,(_via) ? (const char *)0 : _device); + _routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device); #endif // __BSD__ ------------------------------------------------------------ #ifdef __LINUX__ // ---------------------------------------------------------- diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 9c7e8477..4bf56503 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace ZeroTier { @@ -105,7 +105,7 @@ private: InetAddress _target; InetAddress _via; InetAddress _systemVia; // for route overrides - std::set _applied; // routes currently applied + std::map _applied; // routes currently applied char _device[128]; char _systemDevice[128]; // for route overrides }; diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index b443a7fa..5c135636 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -215,7 +215,7 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer) const char *prole = ""; switch(peer->role) { case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break; - case ZT_PEER_ROLE_RELAY: prole = "RELAY"; break; + case ZT_PEER_ROLE_UPSTREAM: prole = "UPSTREAM"; break; case ZT_PEER_ROLE_ROOT: prole = "ROOT"; break; } -- cgit v1.2.3 From d3524f36090c47e11c2647f022b03e27d16aeb13 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 20 Sep 2016 21:21:34 -0700 Subject: Refactor COM stuff a bit, and respond to COM requests a bit more readily for rapid setup. Will need to revisit later. --- node/Constants.hpp | 7 +++- node/IncomingPacket.cpp | 25 +++++------- node/Membership.hpp | 22 +---------- node/Network.cpp | 102 ++++++++++++++++++++++++------------------------ node/Network.hpp | 11 ++---- node/Node.cpp | 2 +- node/Peer.cpp | 8 +--- node/Peer.hpp | 35 ++++++----------- node/SelfAwareness.cpp | 14 +------ node/Switch.cpp | 11 +++--- node/Topology.cpp | 11 +----- 11 files changed, 94 insertions(+), 154 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index b3c3dec0..b7042d5d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -296,7 +296,12 @@ /** * General rate limit timeout for multiple packet types (HELLO, etc.) */ -#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 1000 +#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 500 + +/** + * General limit for max RTT for requests over the network + */ +#define ZT_GENERAL_RTT_LIMIT 5000 /** * Delay between requests for updated network autoconf information diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9bc41d47..b3925773 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -153,28 +153,21 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr break; case Packet::ERROR_IDENTITY_COLLISION: - // Roots are the only peers currently permitted to state authoritatively - // that an identity has collided. When this occurs the node should be shut - // down and a new identity created. The odds of this ever happening are - // very low. + // FIXME: for federation this will need a payload with a signature or something. if (RR->topology->isRoot(peer->identity())) RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - // This error can be sent in response to any packet that fails network - // authorization. We only listen to it if it's from a peer that has recently - // been authorized on this network. + // Peers can send this in response to frames if they do not have a recent enough COM from us SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->recentlyAllowedOnNetwork(peer))) { - const uint64_t now = RR->node->now(); - if (peer->rateGateComRequest(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - network->config().com.serialize(outp); - outp.append((uint8_t)0); - outp.armor(peer->key(),true); - _path->send(RR,outp.data(),outp.size(),now); - } + const uint64_t now = RR->node->now(); + if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + network->config().com.serialize(outp); + outp.append((uint8_t)0); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),now); } } break; diff --git a/node/Membership.hpp b/node/Membership.hpp index d67c6822..5eb68d34 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -154,23 +154,6 @@ public: return nconf.com.agreesWith(_com); } - /** - * @return True if this member has been on this network recently (or network is public) - */ - inline bool recentlyAllowedOnNetwork(const NetworkConfig &nconf) const - { - if (nconf.isPublic()) - return true; - if (_com) { - const uint64_t a = _com.timestamp().first; - if ((_blacklistBefore)&&(a <= _blacklistBefore)) - return false; - const uint64_t b = nconf.com.timestamp().first; - return ((a <= b) ? ((b - a) <= ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA) : true); - } - return false; - } - /** * Check whether a capability or tag is within its max delta from the timestamp of our network config and newer than any blacklist cutoff time * @@ -259,10 +242,7 @@ public: * * @param ts Blacklist cutoff */ - inline void blacklistBefore(const uint64_t ts) - { - _blacklistBefore = ts; - } + inline void blacklistBefore(const uint64_t ts) { _blacklistBefore = ts; } /** * Clean up old or stale entries diff --git a/node/Network.cpp b/node/Network.cpp index 197841d9..455e185e 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -648,11 +648,12 @@ bool Network::filterOutgoingPacket( { uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; - Address ztDest2(ztDest); + Address ztFinalDest(ztDest); Address cc; const Capability *relevantCap = (const Capability *)0; unsigned int ccLength = 0; bool accept = false; + const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -663,26 +664,27 @@ bool Network::filterOutgoingPacket( remoteTagCount = m->getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); } - switch(_doZtFilter(RR,_config,false,ztSource,ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + switch(_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { case DOZTFILTER_NO_MATCH: for(unsigned int c=0;c<_config.capabilityCount;++c) { - ztDest2 = ztDest; // sanity check + ztFinalDest = ztDest; // sanity check Address cc2; unsigned int ccLength2 = 0; - switch (_doZtFilter(RR,_config,false,ztSource,ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + switch (_doZtFilter(RR,_config,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side relevantCap = &(_config.capabilities[c]); accept = true; if ((!noTee)&&(cc2)) { - _membership(cc2).sendCredentialsIfNeeded(RR,RR->node->now(),cc2,_config,relevantCap); + Membership &m2 = _membership(cc2); + m2.sendCredentialsIfNeeded(RR,now,cc2,_config,relevantCap); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -705,7 +707,7 @@ bool Network::filterOutgoingPacket( case DOZTFILTER_DROP: return false; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side accept = true; @@ -714,7 +716,8 @@ bool Network::filterOutgoingPacket( if (accept) { if ((!noTee)&&(cc)) { - _membership(cc).sendCredentialsIfNeeded(RR,RR->node->now(),cc,_config,relevantCap); + Membership &m2 = _membership(cc); + m2.sendCredentialsIfNeeded(RR,now,cc,_config,relevantCap); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -727,10 +730,11 @@ bool Network::filterOutgoingPacket( RR->sw->send(outp,true); } - if ((ztDest != ztDest2)&&(ztDest2)) { - _membership(ztDest2).sendCredentialsIfNeeded(RR,RR->node->now(),ztDest2,_config,relevantCap); + if ((ztDest != ztFinalDest)&&(ztFinalDest)) { + Membership &m2 = _membership(ztFinalDest); + m2.sendCredentialsIfNeeded(RR,now,ztFinalDest,_config,relevantCap); - Packet outp(ztDest2,RR->identity.address(),Packet::VERB_EXT_FRAME); + Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); outp.append((uint8_t)0x02); // TEE/REDIRECT from outbound side: 0x02 macDest.appendTo(outp); @@ -742,11 +746,13 @@ bool Network::filterOutgoingPacket( return false; // DROP locally, since we redirected } else if (m) { - m->sendCredentialsIfNeeded(RR,RR->node->now(),ztDest,_config,relevantCap); + m->sendCredentialsIfNeeded(RR,now,ztDest,_config,relevantCap); } - } - return accept; + return true; + } else { + return false; + } } int Network::filterIncomingPacket( @@ -761,7 +767,7 @@ int Network::filterIncomingPacket( { uint32_t remoteTagIds[ZT_MAX_NETWORK_TAGS]; uint32_t remoteTagValues[ZT_MAX_NETWORK_TAGS]; - Address ztDest2(ztDest); + Address ztFinalDest(ztDest); Address cc; unsigned int ccLength = 0; int accept = 0; @@ -771,16 +777,16 @@ int Network::filterIncomingPacket( Membership &m = _membership(sourcePeer->address()); const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); - switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { + switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc,ccLength)) { case DOZTFILTER_NO_MATCH: { Membership::CapabilityIterator mci(m); const Capability *c; while ((c = mci.next(_config))) { - ztDest2 = ztDest; // sanity check + ztFinalDest = ztDest; // sanity check Address cc2; unsigned int ccLength2 = 0; - switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest2,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { + switch(_doZtFilter(RR,_config,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,cc2,ccLength2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; @@ -815,7 +821,7 @@ int Network::filterIncomingPacket( case DOZTFILTER_DROP: return 0; // DROP - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest2 will have been changed in _doZtFilter() + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: accept = 1; // ACCEPT break; @@ -839,10 +845,10 @@ int Network::filterIncomingPacket( RR->sw->send(outp,true); } - if ((ztDest != ztDest2)&&(ztDest2)) { - _membership(ztDest2).sendCredentialsIfNeeded(RR,RR->node->now(),ztDest2,_config,(const Capability *)0); + if ((ztDest != ztFinalDest)&&(ztFinalDest)) { + _membership(ztFinalDest).sendCredentialsIfNeeded(RR,RR->node->now(),ztFinalDest,_config,(const Capability *)0); - Packet outp(ztDest2,RR->identity.address(),Packet::VERB_EXT_FRAME); + Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); outp.append((uint8_t)0x06); // TEE/REDIRECT from inbound side: 0x06 macDest.appendTo(outp); @@ -1063,23 +1069,26 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin Mutex::Lock _l(_lock); try { if (_config) { - Membership &m = _membership(peer->address()); - const bool allow = m.isAllowedOnNetwork(_config); - if (allow) { - m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); - if (m.shouldLikeMulticasts(now)) { + Membership *m = _memberships.get(peer->address()); + if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) { + if (!m) + m = &(_membership(peer->address())); + m->sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0); + if (m->shouldLikeMulticasts(now)) { _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); - m.likingMulticasts(now); + m->likingMulticasts(now); + } + return true; + } else { + if (peer->rateGateRequestCredentials(now)) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)verb); + outp.append(packetId); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(_id); + RR->sw->send(outp,true); } - } else if (m.recentlyAllowedOnNetwork(_config)&&peer->rateGateRequestCredentials(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb); - outp.append(packetId); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(_id); - RR->sw->send(outp,true); } - return allow; } } catch ( ... ) { TRACE("gate() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); @@ -1092,15 +1101,6 @@ bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet: return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); } -bool Network::recentlyAllowedOnNetwork(const SharedPtr &peer) const -{ - Mutex::Lock _l(_lock); - const Membership *m = _memberships.get(peer->address()); - if (m) - return m->recentlyAllowedOnNetwork(_config); - return false; -} - void Network::clean() { const uint64_t now = RR->node->now(); @@ -1308,13 +1308,11 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - if ( (m->recentlyAllowedOnNetwork(_config)) || (std::find(anchors.begin(),anchors.end(),*a) != anchors.end()) ) { - m->sendCredentialsIfNeeded(RR,RR->node->now(),*a,_config,(const Capability *)0); - if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { - if (!newMulticastGroup) - m->likingMulticasts(now); - _announceMulticastGroupsTo(*a,groups); - } + m->sendCredentialsIfNeeded(RR,now,*a,_config,(const Capability *)0); + if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { + if (!newMulticastGroup) + m->likingMulticasts(now); + _announceMulticastGroupsTo(*a,groups); } } } diff --git a/node/Network.hpp b/node/Network.hpp index 7a4065ff..c85e5993 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -248,7 +248,10 @@ public: void requestConfiguration(); /** - * Membership check gate for incoming packets related to this network + * Determine whether this peer is permitted to communicate on this network + * + * This also performs certain periodic actions such as pushing renewed + * credentials to peers or requesting them if not present. * * @param peer Peer to check * @param verb Packet verb @@ -262,12 +265,6 @@ public: */ bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); - /** - * @param peer Peer to check - * @return True if peer has recently been a valid member of this network - */ - bool recentlyAllowedOnNetwork(const SharedPtr &peer) const; - /** * Perform cleanup and possibly save state */ diff --git a/node/Node.cpp b/node/Node.cpp index 51f1b5c0..2533eeb6 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -241,7 +241,7 @@ public: } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - } else if (p->activelyTransferringFrames(_now)) { + } else if (p->isActive(_now)) { // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently p->doPingAndKeepalive(_now,-1); } diff --git a/node/Peer.cpp b/node/Peer.cpp index 78af9063..d742964a 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -41,7 +41,6 @@ namespace ZeroTier { static uint32_t _natKeepaliveBuf = 0; Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : - _lastUsed(0), _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), @@ -408,19 +407,16 @@ bool Peer::hasActiveDirectPath(uint64_t now) const return false; } -bool Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) +void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) { Mutex::Lock _l(_paths_m); - bool resetSomething = false; for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now); _paths[p].path->sent(now); - _paths[p].lastReceive >>= 2; // de-prioritize heavily vs. other paths, will get reset if we get OK(HELLO) or other traffic - resetSomething = true; + _paths[p].lastReceive = 0; // path will not be used unless it speaks again } } - return resetSomething; } void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const diff --git a/node/Peer.hpp b/node/Peer.hpp index 1ae239bc..c5ef43ed 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -68,18 +68,6 @@ public: */ Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity); - /** - * @return Time peer record was last used in any way - */ - inline uint64_t lastUsed() const throw() { return _lastUsed; } - - /** - * Log a use of this peer record (done by Topology when peers are looked up) - * - * @param now New time of last use - */ - inline void use(uint64_t now) throw() { _lastUsed = now; } - /** * @return This peer's ZT address (short for identity().address()) */ @@ -194,15 +182,14 @@ public: /** * Reset paths within a given IP scope and address family * - * Resetting a path involves sending a HELLO to it and then de-prioritizing - * it vs. other paths. + * Resetting a path involves sending an ECHO to it and then deactivating + * it until or unless it responds. * * @param scope IP scope * @param inetAddressFamily Family e.g. AF_INET * @param now Current time - * @return True if we forgot at least one path */ - bool resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + void resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); /** * Get most recently active path addresses for IPv4 and/or IPv6 @@ -232,27 +219,32 @@ public: /** * @return Time of last receive of anything, whether direct or relayed */ - inline uint64_t lastReceive() const throw() { return _lastReceive; } + inline uint64_t lastReceive() const { return _lastReceive; } + + /** + * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT + */ + inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Time of most recent unicast frame received */ - inline uint64_t lastUnicastFrame() const throw() { return _lastUnicastFrame; } + inline uint64_t lastUnicastFrame() const { return _lastUnicastFrame; } /** * @return Time of most recent multicast frame received */ - inline uint64_t lastMulticastFrame() const throw() { return _lastMulticastFrame; } + inline uint64_t lastMulticastFrame() const { return _lastMulticastFrame; } /** * @return Time of most recent frame of any kind (unicast or multicast) */ - inline uint64_t lastFrame() const throw() { return std::max(_lastUnicastFrame,_lastMulticastFrame); } + inline uint64_t lastFrame() const { return std::max(_lastUnicastFrame,_lastMulticastFrame); } /** * @return True if this peer has sent us real network traffic recently */ - inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline uint64_t isActive(uint64_t now) const { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Latency in milliseconds or 0 if unknown @@ -464,7 +456,6 @@ private: uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t _remoteClusterOptimal6[16]; - uint64_t _lastUsed; uint64_t _lastReceive; // direct or indirect uint64_t _lastUnicastFrame; uint64_t _lastMulticastFrame; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 6bf50720..e84b7b65 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -45,9 +45,7 @@ public: _family(inetAddressFamily), _scope(scope) {} - inline void operator()(Topology &t,const SharedPtr &p) { if (p->resetWithinScope(_scope,_family,_now)) peersReset.push_back(p); } - - std::vector< SharedPtr > peersReset; + inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_scope,_family,_now); } private: uint64_t _now; @@ -95,16 +93,6 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc // Reset all paths within this scope and address family _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); - - // Send a NOP to all peers for whom we forgot a path. This will cause direct - // links to be re-established if possible, possibly using a root server or some - // other relay. - for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { - if ((*p)->activelyTransferringFrames(now)) { - Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true); - } - } } else { // Otherwise just update DB to use to determine external surface info entry.mySurface = myPhysicalAddress; diff --git a/node/Switch.cpp b/node/Switch.cpp index beb36b6c..e3d57835 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -354,8 +354,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c return; } - // Destination is a multicast address (including broadcast) - MulticastGroup mg(to,0); + MulticastGroup multicastGroup(to,0); if (to.isBroadcast()) { if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) { @@ -368,7 +367,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * them into multicasts by stuffing the IP address being queried into * the 32-bit ADI field. In practice this uses our multicast pub/sub * system to implement a kind of extended/distributed ARP table. */ - mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); + multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); @@ -463,9 +462,9 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * multicast addresses on bridge interfaces and subscribing each slave. * But in that case this does no harm, as the sets are just merged. */ if (fromBridged) - network->learnBridgedMulticastGroup(mg,RR->node->now()); + network->learnBridgedMulticastGroup(multicastGroup,RR->node->now()); - //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len); + //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { @@ -478,7 +477,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c RR->node->now(), network->id(), network->config().activeBridges(), - mg, + multicastGroup, (fromBridged) ? from : MAC(), etherType, data, diff --git a/node/Topology.cpp b/node/Topology.cpp index 6e2fd071..12a7cc0b 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -96,7 +96,6 @@ SharedPtr Topology::addPeer(const SharedPtr &peer) np = hp; } - np->use(RR->node->now()); saveIdentity(np->identity()); return np; @@ -113,7 +112,6 @@ SharedPtr Topology::getPeer(const Address &zta) Mutex::Lock _l(_lock); const SharedPtr *const ap = _peers.get(zta); if (ap) { - (*ap)->use(RR->node->now()); return *ap; } } @@ -127,7 +125,6 @@ SharedPtr Topology::getPeer(const Address &zta) SharedPtr &ap = _peers[zta]; if (!ap) ap.swap(np); - ap->use(RR->node->now()); return ap; } } @@ -176,10 +173,8 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou if (_rootAddresses[p] == RR->identity.address()) { for(unsigned long q=1;q<_rootAddresses.size();++q) { const SharedPtr *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]); - if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) { - (*nextsn)->use(now); + if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) return *nextsn; - } } break; } @@ -214,10 +209,8 @@ SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCou } if (bestNotAvoid) { - (*bestNotAvoid)->use(now); return *bestNotAvoid; } else if ((!strictAvoid)&&(bestOverall)) { - (*bestOverall)->use(now); return *bestOverall; } @@ -256,7 +249,7 @@ void Topology::clean(uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) + if ( (!(*p)->isAlive(now)) && (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) ) _peers.erase(*a); } } -- cgit v1.2.3 From 9f550292fe0ebc32e61eeada9e3a69970c874724 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 27 Sep 2016 13:49:43 -0700 Subject: Simply network auth logic and always sent error on auth failure even for unknown networks to prevent forensics. --- node/IncomingPacket.cpp | 61 ++++++++++++++++++++++++++++++------------------- node/IncomingPacket.hpp | 2 ++ node/Network.cpp | 21 +++-------------- node/Network.hpp | 15 +----------- node/Node.hpp | 8 ++++--- node/Peer.cpp | 1 + node/Peer.hpp | 17 ++++++++++++-- 7 files changed, 64 insertions(+), 61 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0a3d58af..f54752d1 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -169,7 +169,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Peers can send this in response to frames if they do not have a recent enough COM from us const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); - if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) + if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(peer->address(),now); } break; @@ -184,7 +184,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->gate(peer,verb(),packetId()))) { + if ((network)&&(network->gate(peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); @@ -375,7 +375,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - bool trustEstablished = false; if (!RR->node->expectingReplyTo(inRePacketId)) { TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); @@ -441,8 +440,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { - trustEstablished = true; + if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -468,15 +466,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->addCredential(com); } - if (network->gateMulticastGatherReply(peer,verb(),packetId())) { - trustEstablished = true; - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); - } + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); offset += 4; + unsigned int count = at(offset); offset += 2; + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -484,7 +479,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,trustEstablished); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -581,9 +576,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const SharedPtr network(RR->node->network(nwid)); bool trustEstablished = false; if (network) { - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - } else { + if (network->gate(peer)) { trustEstablished = true; if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); @@ -593,9 +586,13 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } + } else { + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + _sendErrorNeedCredentials(RR,peer,nwid); } peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { @@ -620,8 +617,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

addCredential(com); } - if (!network->gate(peer,verb(),packetId())) { + if (!network->gate(peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -681,6 +679,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { @@ -737,7 +736,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (!auth) { if ((!network)||(network->id() != nwid)) network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(peer,verb(),packetId()))); + const bool authOnNet = ((network)&&(network->gate(peer))); trustEstablished |= authOnNet; if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; @@ -986,7 +985,6 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1020,7 +1018,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar } } - const bool trustEstablished = ((network)&&(network->gate(peer,verb(),packetId()))); + const bool trustEstablished = ((network)&&(network->gate(peer))); if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); @@ -1067,8 +1065,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->addCredential(com); } - if (!network->gate(peer,verb(),packetId())) { + if (!network->gate(peer)) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -1143,6 +1142,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { @@ -1288,7 +1288,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } - if (network->gate(peer,verb(),packetId())) + if (network->gate(peer)) reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); @@ -1479,6 +1479,19 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const return true; } +void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) +{ + if (peer->rateGateOutgoingComRequest(RR->node->now())) { + Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)verb()); + outp.append(packetId()); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(nwid); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + } +} + 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 diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 86c2b5e7..c3632216 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -154,6 +154,8 @@ private: bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer); + void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); + uint64_t _receiveTime; SharedPtr _path; }; diff --git a/node/Network.cpp b/node/Network.cpp index 601395d0..52abbcf9 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -50,6 +50,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP"; case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT"; case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE"; + case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH"; case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT"; case ZT_NETWORK_RULE_ACTION_DEBUG_LOG: return "ACTION_DEBUG_LOG"; case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS"; @@ -882,7 +883,7 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) const unsigned int start = ptr; ptr += 8; // skip network ID, which is already obviously known - const uint16_t chunkLen = chunk.at(ptr); ptr += 2; + const unsigned int chunkLen = chunk.at(ptr); ptr += 2; const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen; Mutex::Lock _l(_lock); @@ -975,8 +976,6 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) if (c->updateId != configUpdateId) { c->updateId = configUpdateId; - for(int i=0;ihaveChunkIds[i] = 0; c->haveChunks = 0; c->haveBytes = 0; } @@ -1065,7 +1064,7 @@ void Network::requestConfiguration() RR->sw->send(outp,true); } -bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +bool Network::gate(const SharedPtr &peer) { const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -1081,15 +1080,6 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin m->likingMulticasts(now); } return true; - } else { - if (peer->rateGateRequestCredentials(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb); - outp.append(packetId); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(_id); - RR->sw->send(outp,true); - } } } } catch ( ... ) { @@ -1098,11 +1088,6 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } -bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) -{ - return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); -} - void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index 128c4668..527d3048 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -212,21 +212,8 @@ public: /** * Determine whether this peer is permitted to communicate on this network - * - * This also performs certain periodic actions such as pushing renewed - * credentials to peers, so like the filters it is not side-effect-free. - * - * @param peer Peer to check - * @param verb Packet verb - * @param packetId Packet ID - * @return True if peer is allowed to communicate on this network - */ - bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); - - /** - * Check whether this peer is allowed to provide multicast info for this network */ - bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + bool gate(const SharedPtr &peer); /** * Do periodic cleanup and housekeeping tasks diff --git a/node/Node.hpp b/node/Node.hpp index 11462531..ddc52651 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -267,17 +267,19 @@ public: } /** - * Check whether a given packet ID is something we are expecting a reply to + * Check whether a given packet ID is something we are expecting a reply to (and erase from list) * * @param packetId Packet ID to check * @return True if we're expecting a reply */ - inline bool expectingReplyTo(const uint64_t packetId) const + inline bool expectingReplyTo(const uint64_t packetId) { const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == packetId) + if (_expectingRepliesTo[bucket][i] == packetId) { + _expectingRepliesTo[bucket][i] = 0; return true; + } } return false; } diff --git a/node/Peer.cpp b/node/Peer.cpp index d742964a..87882dad 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -50,6 +50,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), _lastComRequestReceived(0), + _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), RR(renv), diff --git a/node/Peer.hpp b/node/Peer.hpp index c5ef43ed..d0589ccf 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -395,9 +395,9 @@ public: } /** - * Rate gate requests for network COM + * Rate gate incoming requests for network COM */ - inline bool rateGateComRequest(const uint64_t now) + inline bool rateGateIncomingComRequest(const uint64_t now) { if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestReceived = now; @@ -406,6 +406,18 @@ public: return false; } + /** + * Rate gate outgoing requests for network COM + */ + inline bool rateGateOutgoingComRequest(const uint64_t now) + { + if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastComRequestSent = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -465,6 +477,7 @@ private: uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; + uint64_t _lastComRequestSent; uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; const RuntimeEnvironment *RR; -- cgit v1.2.3 From c61ca1dea2001d8b77bf6b1f44da4246c3088e32 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 9 Nov 2016 16:04:08 -0800 Subject: Keep connections up for netconf stuff as well as frames. --- include/ZeroTierOne.h | 10 ---------- node/Node.cpp | 2 -- node/Peer.cpp | 17 +++++++++++------ node/Peer.hpp | 20 ++------------------ service/ControlPlane.cpp | 4 ---- service/README.md | 2 -- 6 files changed, 13 insertions(+), 42 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 17112e90..d0fef1f1 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1018,16 +1018,6 @@ typedef struct */ uint64_t address; - /** - * Time we last received a unicast frame from this peer - */ - uint64_t lastUnicastFrame; - - /** - * Time we last received a multicast rame from this peer - */ - uint64_t lastMulticastFrame; - /** * Remote major version or -1 if not known */ diff --git a/node/Node.cpp b/node/Node.cpp index db9b8ea0..9314478f 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -405,8 +405,6 @@ ZT_PeerList *Node::peers() const for(std::vector< std::pair< Address,SharedPtr > >::iterator pi(peers.begin());pi!=peers.end();++pi) { ZT_Peer *p = &(pl->peers[pl->peerCount++]); p->address = pi->second->address().toInt(); - p->lastUnicastFrame = pi->second->lastUnicastFrame(); - p->lastMulticastFrame = pi->second->lastMulticastFrame(); if (pi->second->remoteVersionKnown()) { p->versionMajor = pi->second->remoteVersionMajor(); p->versionMinor = pi->second->remoteVersionMinor(); diff --git a/node/Peer.cpp b/node/Peer.cpp index 87882dad..94fb5298 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -42,8 +42,7 @@ static uint32_t _natKeepaliveBuf = 0; Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : _lastReceive(0), - _lastUnicastFrame(0), - _lastMulticastFrame(0), + _lastNontrivialReceive(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), _lastCredentialRequestSent(0), @@ -128,10 +127,16 @@ void Peer::received( #endif _lastReceive = now; - if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME)) - _lastUnicastFrame = now; - else if (verb == Packet::VERB_MULTICAST_FRAME) - _lastMulticastFrame = now; + switch (verb) { + case Packet::VERB_FRAME: + case Packet::VERB_EXT_FRAME: + case Packet::VERB_NETWORK_CONFIG_REQUEST: + case Packet::VERB_NETWORK_CONFIG: + case Packet::VERB_MULTICAST_FRAME: + _lastNontrivialReceive = now; + break; + default: break; + } if (trustEstablished) { _lastTrustEstablishedPacketReceived = now; diff --git a/node/Peer.hpp b/node/Peer.hpp index d0589ccf..be05aa3a 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -226,25 +226,10 @@ public: */ inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } - /** - * @return Time of most recent unicast frame received - */ - inline uint64_t lastUnicastFrame() const { return _lastUnicastFrame; } - - /** - * @return Time of most recent multicast frame received - */ - inline uint64_t lastMulticastFrame() const { return _lastMulticastFrame; } - - /** - * @return Time of most recent frame of any kind (unicast or multicast) - */ - inline uint64_t lastFrame() const { return std::max(_lastUnicastFrame,_lastMulticastFrame); } - /** * @return True if this peer has sent us real network traffic recently */ - inline uint64_t isActive(uint64_t now) const { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline uint64_t isActive(uint64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Latency in milliseconds or 0 if unknown @@ -469,8 +454,7 @@ private: uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t _remoteClusterOptimal6[16]; uint64_t _lastReceive; // direct or indirect - uint64_t _lastUnicastFrame; - uint64_t _lastMulticastFrame; + uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; uint64_t _lastCredentialRequestSent; diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 5c135636..f14bae54 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -222,8 +222,6 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer) Utils::snprintf(json,sizeof(json), "%s{\n" "%s\t\"address\": \"%.10llx\",\n" - "%s\t\"lastUnicastFrame\": %llu,\n" - "%s\t\"lastMulticastFrame\": %llu,\n" "%s\t\"versionMajor\": %d,\n" "%s\t\"versionMinor\": %d,\n" "%s\t\"versionRev\": %d,\n" @@ -234,8 +232,6 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer) "%s}", prefix, prefix,peer->address, - prefix,peer->lastUnicastFrame, - prefix,peer->lastMulticastFrame, prefix,peer->versionMajor, prefix,peer->versionMinor, prefix,peer->versionRev, diff --git a/service/README.md b/service/README.md index 1c71fbdc..f487f2bc 100644 --- a/service/README.md +++ b/service/README.md @@ -114,8 +114,6 @@ Getting /peer returns an array of peer objects for all current peers. See below - - -- cgit v1.2.3 From 42ba70e79e3f1484f7bdde5832658cbd179649dc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 22 Nov 2016 10:54:58 -0800 Subject: Replace long callback arg list with struct, and implement path whitelisting, path blacklisting, and local.conf support for roles. --- include/ZeroTierOne.h | 97 ++++++++++++++++---- node/IncomingPacket.cpp | 6 +- node/Node.cpp | 88 ++++++------------ node/Node.hpp | 86 +++-------------- node/Peer.cpp | 2 +- node/Switch.cpp | 2 +- service/OneService.cpp | 238 ++++++++++++++++++++++++++++++++++++------------ 7 files changed, 302 insertions(+), 217 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 399f090c..72da53f2 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1495,8 +1495,9 @@ typedef int (*ZT_WirePacketSendFunction)( * Paramters: * (1) Node * (2) User pointer - * (3) Local interface address - * (4) Remote address + * (3) ZeroTier address or 0 for none/any + * (4) Local interface address + * (5) Remote address * * This function must return nonzero (true) if the path should be used. * @@ -1515,13 +1516,87 @@ typedef int (*ZT_WirePacketSendFunction)( typedef int (*ZT_PathCheckFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + uint64_t, /* ZeroTier address */ const struct sockaddr_storage *, /* Local address */ const struct sockaddr_storage *); /* Remote address */ +/** + * Function to get physical addresses for ZeroTier peers + * + * Parameters: + * (1) Node + * (2) User pointer + * (3) ZeroTier address (least significant 40 bits) + * (4) Desried address family or -1 for any + * (5) Buffer to fill with result + * + * If provided this function will be occasionally called to get physical + * addresses that might be tried to reach a ZeroTier address. It must + * return a nonzero (true) value if the result buffer has been filled + * with an address. + */ +typedef int (*ZT_PathLookupFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + uint64_t, /* ZeroTier address (40 bits) */ + int, /* Desired ss_family or -1 for any */ + struct sockaddr_storage *); /* Result buffer */ + /****************************************************************************/ /* C Node API */ /****************************************************************************/ +/** + * Structure for configuring ZeroTier core callback functions + */ +struct ZT_Node_Callbacks +{ + /** + * Struct version -- must currently be 0 + */ + long version; + + /** + * REQUIRED: Function to get objects from persistent storage + */ + ZT_DataStoreGetFunction dataStoreGetFunction; + + /** + * REQUIRED: Function to store objects in persistent storage + */ + ZT_DataStorePutFunction dataStorePutFunction; + + /** + * REQUIRED: Function to send packets over the physical wire + */ + ZT_WirePacketSendFunction wirePacketSendFunction; + + /** + * REQUIRED: Function to inject frames into a virtual network's TAP + */ + ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; + + /** + * REQUIRED: Function to be called when virtual networks are configured or changed + */ + ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; + + /** + * REQUIRED: Function to be called to notify external code of important events + */ + ZT_EventCallback eventCallback; + + /** + * OPTIONAL: Function to check whether a given physical path should be used + */ + ZT_PathCheckFunction pathCheckFunction; + + /** + * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses + */ + ZT_PathLookupFunction pathLookupFunction; +}; + /** * Create a new ZeroTier One node * @@ -1533,25 +1608,11 @@ typedef int (*ZT_PathCheckFunction)( * * @param node Result: pointer is set to new node instance on success * @param uptr User pointer to pass to functions/callbacks + * @param callbacks Callback function configuration * @param now Current clock in milliseconds - * @param dataStoreGetFunction Function called to get objects from persistent storage - * @param dataStorePutFunction Function called to put objects in persistent storage - * @param virtualNetworkConfigFunction Function to be called when virtual LANs are created, deleted, or their config parameters change - * @param pathCheckFunction A function to check whether a path should be used for ZeroTier traffic, or NULL to allow any path - * @param eventCallback Function to receive status updates and non-fatal error notices * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_new( - ZT_Node **node, - void *uptr, - uint64_t now, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback); +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); /** * Delete a node and free all resources it consumes diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 41f3e47d..7b828f8b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -552,7 +552,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) { + if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1120,7 +1120,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(InetAddress(),a,now); @@ -1139,7 +1139,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(InetAddress(),a,now); diff --git a/node/Node.cpp b/node/Node.cpp index 263cfc6e..a180766b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,34 +46,20 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node( - uint64_t now, - void *uptr, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback) : +Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : _RR(this), RR(&_RR), _uPtr(uptr), - _dataStoreGetFunction(dataStoreGetFunction), - _dataStorePutFunction(dataStorePutFunction), - _wirePacketSendFunction(wirePacketSendFunction), - _virtualNetworkFrameFunction(virtualNetworkFrameFunction), - _virtualNetworkConfigFunction(virtualNetworkConfigFunction), - _pathCheckFunction(pathCheckFunction), - _eventCallback(eventCallback), - _networks(), - _networks_m(), _prngStreamPtr(0), _now(now), _lastPingCheck(0), _lastHousekeepingRun(0), _relayPolicy(ZT_RELAY_POLICY_TRUSTED) { + if (callbacks->version != 0) + throw std::runtime_error("callbacks struct version mismatch"); + memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); + _online = false; memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); @@ -81,30 +67,26 @@ Node::Node( memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); // Use Salsa20 alone as a high-quality non-crypto PRNG - { - char foo[32]; - Utils::getSecureRandom(foo,32); - _prng.init(foo,256,foo); - memset(_prngStream,0,sizeof(_prngStream)); - _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + char foo[32]; + Utils::getSecureRandom(foo,32); + _prng.init(foo,256,foo); + memset(_prngStream,0,sizeof(_prngStream)); + _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + + std::string idtmp(dataStoreGet("identity.secret")); + if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { + TRACE("identity.secret not found, generating..."); + RR->identity.generate(); + idtmp = RR->identity.toString(true); + if (!dataStorePut("identity.secret",idtmp,true)) + throw std::runtime_error("unable to write identity.secret"); } - - { - std::string idtmp(dataStoreGet("identity.secret")); - if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { - TRACE("identity.secret not found, generating..."); - RR->identity.generate(); - idtmp = RR->identity.toString(true); - if (!dataStorePut("identity.secret",idtmp,true)) - throw std::runtime_error("unable to write identity.secret"); - } - RR->publicIdentityStr = RR->identity.toString(false); - RR->secretIdentityStr = RR->identity.toString(true); - idtmp = dataStoreGet("identity.public"); - if (idtmp != RR->publicIdentityStr) { - if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) - throw std::runtime_error("unable to write identity.public"); - } + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + idtmp = dataStoreGet("identity.public"); + if (idtmp != RR->publicIdentityStr) { + if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) + throw std::runtime_error("unable to write identity.public"); } try { @@ -638,7 +620,7 @@ std::string Node::dataStoreGet(const char *name) std::string r; unsigned long olen = 0; do { - long n = _dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); + long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); @@ -646,7 +628,7 @@ std::string Node::dataStoreGet(const char *name) return r; } -bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) { if (!Path::isAddressValidForPath(remoteAddress)) return false; @@ -663,9 +645,7 @@ bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const } } - if (_pathCheckFunction) - return (_pathCheckFunction(reinterpret_cast(this),_uPtr,reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0); - else return true; + return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); } #ifdef ZT_TRACE @@ -822,21 +802,11 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new( - ZT_Node **node, - void *uptr, - uint64_t now, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback) +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) { *node = (ZT_Node *)0; try { - *node = reinterpret_cast(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,pathCheckFunction,eventCallback)); + *node = reinterpret_cast(new ZeroTier::Node(uptr,callbacks,now)); return ZT_RESULT_OK; } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; diff --git a/node/Node.hpp b/node/Node.hpp index 38303f8c..7d99ff09 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -59,17 +59,7 @@ namespace ZeroTier { class Node : public NetworkController::Sender { public: - Node( - uint64_t now, - void *uptr, - ZT_DataStoreGetFunction dataStoreGetFunction, - ZT_DataStorePutFunction dataStorePutFunction, - ZT_WirePacketSendFunction wirePacketSendFunction, - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction, - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction, - ZT_PathCheckFunction pathCheckFunction, - ZT_EventCallback eventCallback); - + Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); virtual ~Node(); // Public API Functions ---------------------------------------------------- @@ -127,24 +117,11 @@ public: // Internal functions ------------------------------------------------------ - /** - * @return Time as of last call to run() - */ inline uint64_t now() const throw() { return _now; } - /** - * Enqueue a ZeroTier message to be sent - * - * @param localAddress Local address - * @param addr Destination address - * @param data Packet data - * @param len Packet length - * @param ttl Desired TTL (default: 0 for unchanged/default TTL) - * @return True if packet appears to have been sent - */ inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { - return (_wirePacketSendFunction( + return (_cb.wirePacketSendFunction( reinterpret_cast(this), _uPtr, reinterpret_cast(&localAddress), @@ -154,21 +131,9 @@ public: ttl) == 0); } - /** - * Enqueue a frame to be injected into a tap device (port) - * - * @param nwid Network ID - * @param nuptr Network user ptr - * @param source Source MAC - * @param dest Destination MAC - * @param etherType 16-bit ethernet type - * @param vlanId VLAN ID or 0 if none - * @param data Frame data - * @param len Frame length - */ inline void putFrame(uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { - _virtualNetworkFrameFunction( + _cb.virtualNetworkFrameFunction( reinterpret_cast(this), _uPtr, nwid, @@ -181,13 +146,6 @@ public: len); } - /** - * @param localAddress Local address - * @param remoteAddress Remote address - * @return True if path should be used - */ - bool shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress); - inline SharedPtr network(uint64_t nwid) const { Mutex::Lock _l(_networks_m); @@ -214,37 +172,20 @@ public: return nw; } - /** - * @return Potential direct paths to me a.k.a. local interface addresses - */ inline std::vector directPaths() const { Mutex::Lock _l(_directPaths_m); return _directPaths; } - inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } + inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } - inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } + inline void dataStoreDelete(const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } std::string dataStoreGet(const char *name); - /** - * Post an event to the external user - * - * @param ev Event type - * @param md Meta-data (default: NULL/none) - */ - inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _eventCallback(reinterpret_cast(this),_uPtr,ev,md); } + inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,ev,md); } - /** - * Update virtual network port configuration - * - * @param nwid Network ID - * @param nuptr Network user ptr - * @param op Configuration operation - * @param nc Network configuration - */ - inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } + inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } inline bool online() const throw() { return _online; } inline ZT_RelayPolicy relayPolicy() const { return _relayPolicy; } @@ -253,6 +194,9 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif + bool shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); + inline bool getPathHint(const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } + uint64_t prng(); void postCircuitTestReport(const ZT_CircuitTestReport *report); void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); @@ -317,8 +261,8 @@ private: RuntimeEnvironment _RR; RuntimeEnvironment *RR; - void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P + ZT_Node_Callbacks _cb; // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; @@ -327,14 +271,6 @@ private: // Time of last identity verification indexed by InetAddress.rateGateHash() uint64_t _lastIdentityVerification[16384]; - ZT_DataStoreGetFunction _dataStoreGetFunction; - ZT_DataStorePutFunction _dataStorePutFunction; - ZT_WirePacketSendFunction _wirePacketSendFunction; - ZT_VirtualNetworkFrameFunction _virtualNetworkFrameFunction; - ZT_VirtualNetworkConfigFunction _virtualNetworkConfigFunction; - ZT_PathCheckFunction _pathCheckFunction; - ZT_EventCallback _eventCallback; - std::vector< std::pair< uint64_t, SharedPtr > > _networks; Mutex _networks_m; diff --git a/node/Peer.cpp b/node/Peer.cpp index 94fb5298..e0bd0eac 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -160,7 +160,7 @@ void Peer::received( } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address())) ) { + if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); diff --git a/node/Switch.cpp b/node/Switch.cpp index a5dd57e4..881d7b92 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -85,7 +85,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from Address beaconAddr(reinterpret_cast(data) + 8,5); if (beaconAddr == RR->identity.address()) return; - if (!RR->node->shouldUsePathForZeroTierTraffic(localAddr,fromAddr)) + if (!RR->node->shouldUsePathForZeroTierTraffic(beaconAddr,localAddr,fromAddr)) return; SharedPtr peer(RR->topology->getPeer(beaconAddr)); if (peer) { // we'll only respond to beacons from known peers diff --git a/service/OneService.cpp b/service/OneService.cpp index efb6ff3c..7434ca67 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -160,7 +160,6 @@ static uint64_t _jI(const json &jv,const uint64_t dfl) } return dfl; } -/* static bool _jB(const json &jv,const bool dfl) { if (jv.is_boolean()) { @@ -181,7 +180,6 @@ static bool _jB(const json &jv,const bool dfl) } return dfl; } -*/ static std::string _jS(const json &jv,const char *dfl) { if (jv.is_string()) { @@ -452,7 +450,8 @@ static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name, static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure); static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); #ifdef ZT_ENABLE_CLUSTER static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len); @@ -536,11 +535,20 @@ public: const std::string _homePath; BackgroundResolver _tcpFallbackResolver; InetAddress _allowManagementFrom; - json _localConfig; EmbeddedNetworkController *_controller; Phy _phy; Node *_node; + // Local configuration and memo-ized static path definitions + json _localConfig; + Hashtable< uint64_t,std::vector > _v4Hints; + Hashtable< uint64_t,std::vector > _v6Hints; + Hashtable< uint64_t,std::vector > _v4Blacklists; + Hashtable< uint64_t,std::vector > _v6Blacklists; + std::vector< InetAddress > _globalV4Blacklist; + std::vector< InetAddress > _globalV6Blacklist; + Mutex _localConfig_m; + /* * To attempt to handle NAT/gateway craziness we use three local UDP ports: * @@ -552,7 +560,6 @@ public: * destructively with uPnP port mapping behavior in very weird buggy ways. * It's only used if uPnP/NAT-PMP is enabled in this build. */ - Binder _bindings[3]; unsigned int _ports[3]; uint16_t _portsBE[3]; // ports in big-endian network byte order as in sockaddr @@ -756,16 +763,19 @@ public: // Clean up any legacy files if present OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + "peers.save").c_str()); - _node = new Node( - OSUtils::now(), - this, - SnodeDataStoreGetFunction, - SnodeDataStorePutFunction, - SnodeWirePacketSendFunction, - SnodeVirtualNetworkFrameFunction, - SnodeVirtualNetworkConfigFunction, - SnodePathCheckFunction, - SnodeEventCallback); + { + struct ZT_Node_Callbacks cb; + cb.version = 0; + cb.dataStoreGetFunction = SnodeDataStoreGetFunction; + cb.dataStorePutFunction = SnodeDataStorePutFunction; + cb.wirePacketSendFunction = SnodeWirePacketSendFunction; + cb.virtualNetworkFrameFunction = SnodeVirtualNetworkFrameFunction; + cb.virtualNetworkConfigFunction = SnodeVirtualNetworkConfigFunction; + cb.eventCallback = SnodeEventCallback; + cb.pathCheckFunction = SnodePathCheckFunction; + cb.pathLookupFunction = SnodePathLookupFunction; + _node = new Node(this,&cb,OSUtils::now()); + } // Attempt to bind to a secondary port chosen from our ZeroTier address. // This exists because there are buggy NATs out there that fail if more @@ -842,6 +852,7 @@ public: } // Read local config file + Mutex::Lock _l2(_localConfig_m); std::string lcbuf; if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "local.conf").c_str(),lcbuf)) { try { @@ -854,19 +865,18 @@ public: } } - // Get any trusted paths in local.conf + // Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere) json &physical = _localConfig["physical"]; if (physical.is_object()) { for(json::iterator phy(physical.begin());phy!=physical.end();++phy) { - std::string nstr = phy.key(); - if (nstr.length()) { + InetAddress net(_jS(phy.key(),"")); + if (net) { if (phy.value().is_object()) { - uint64_t tpid = 0; - if ((tpid = _jI(phy.value()["trustedPathId"],0ULL))) { - InetAddress trustedPathNetwork(nstr); - if ( ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (trustedPathNetwork.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (trustedPathNetwork.netmaskBits() > 0) ) { + uint64_t tpid; + if ((tpid = _jI(phy.value()["trustedPathId"],0ULL)) != 0ULL) { + if ( ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (net.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (net.netmaskBits() > 0) ) { trustedPathIds[trustedPathCount] = tpid; - trustedPathNetworks[trustedPathCount] = trustedPathNetwork; + trustedPathNetworks[trustedPathCount] = net; ++trustedPathCount; } } @@ -878,31 +888,8 @@ public: // Set trusted paths if there are any if (trustedPathCount) _node->setTrustedPaths(reinterpret_cast(trustedPathNetworks),trustedPathIds,trustedPathCount); - - // Set any roles (upstream/federation) - json &virt = _localConfig["virtual"]; - if (virt.is_object()) { - for(json::iterator v(virt.begin());v!=virt.end();++v) { - const std::string nstr = v.key(); - if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { - const Address ztaddr(nstr.c_str()); - if (ztaddr) - _node->setRole(ztaddr.toInt(),(_jS(v.value()["role"],"") == "upstream") ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); - } - } - } - - // Set any other local config stuff - json &settings = _localConfig["settings"]; - if (settings.is_object()) { - const std::string rp(_jS(settings["relayPolicy"],"")); - if (rp == "always") - _node->setRelayPolicy(ZT_RELAY_POLICY_ALWAYS); - else if (rp == "never") - _node->setRelayPolicy(ZT_RELAY_POLICY_NEVER); - else _node->setRelayPolicy(ZT_RELAY_POLICY_TRUSTED); - } } + applyLocalConfig(); _controller = new EmbeddedNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str()); _node->setNetconfMaster((void *)_controller); @@ -1174,7 +1161,90 @@ public: return true; } - // Begin private implementation methods + // Internal implementation methods ----------------------------------------- + + void applyLocalConfig() + { + Mutex::Lock _l(_localConfig_m); + + _v4Hints.clear(); + _v6Hints.clear(); + _v4Blacklists.clear(); + _v6Blacklists.clear(); + json &virt = _localConfig["virtual"]; + if (virt.is_object()) { + for(json::iterator v(virt.begin());v!=virt.end();++v) { + const std::string nstr = v.key(); + if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { + const Address ztaddr(nstr.c_str()); + if (ztaddr) { + _node->setRole(ztaddr.toInt(),(_jS(v.value()["role"],"") == "upstream") ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); + + const uint64_t ztaddr2 = ztaddr.toInt(); + std::vector &v4h = _v4Hints[ztaddr2]; + std::vector &v6h = _v6Hints[ztaddr2]; + std::vector &v4b = _v4Blacklists[ztaddr2]; + std::vector &v6b = _v6Blacklists[ztaddr2]; + + json &tryAddrs = v.value()["try"]; + if (tryAddrs.is_array()) { + for(unsigned long i=0;i 0)) { + if (phy.value().is_object()) { + if (_jB(phy.value()["blacklist"],false)) { + if (net.ss_family == AF_INET) + _globalV4Blacklist.push_back(net); + else if (net.ss_family == AF_INET6) + _globalV6Blacklist.push_back(net); + } + } + } + } + } + + json &settings = _localConfig["settings"]; + if (settings.is_object()) { + const std::string rp(_jS(settings["relayPolicy"],"")); + if (rp == "always") + _node->setRelayPolicy(ZT_RELAY_POLICY_ALWAYS); + else if (rp == "never") + _node->setRelayPolicy(ZT_RELAY_POLICY_NEVER); + else _node->setRelayPolicy(ZT_RELAY_POLICY_TRUSTED); + } + } // Checks if a managed IP or route target is allowed bool checkIfManagedIsAllowed(const NetworkState &n,const InetAddress &target) @@ -1306,6 +1376,8 @@ public: } } + // Handlers for Node and Phy<> callbacks ----------------------------------- + inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) { #ifdef ZT_ENABLE_CLUSTER @@ -1783,21 +1855,48 @@ public: n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); } - inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) + inline int nodePathCheckFunction(uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) { - Mutex::Lock _l(_nets_m); - - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap) { - std::vector ips(n->second.tap->ips()); - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { - return 0; + // Make sure we're not trying to do ZeroTier-over-ZeroTier + { + Mutex::Lock _l(_nets_m); + for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { + if (n->second.tap) { + std::vector ips(n->second.tap->ips()); + for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { + if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { + return 0; + } } } } } - + + // Check blacklists + const Hashtable< uint64_t,std::vector > *blh = (const Hashtable< uint64_t,std::vector > *)0; + const std::vector *gbl = (const std::vector *)0; + if (remoteAddr->ss_family == AF_INET) { + blh = &_v4Blacklists; + gbl = &_globalV4Blacklist; + } else if (remoteAddr->ss_family == AF_INET6) { + blh = &_v6Blacklists; + gbl = &_globalV6Blacklist; + } + if (blh) { + Mutex::Lock _l(_localConfig_m); + const std::vector *l = blh->get(ztaddr); + if (l) { + for(std::vector::const_iterator a(l->begin());a!=l->end();++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + /* Note: I do not think we need to scan for overlap with managed routes * because of the "route forking" and interface binding that we do. This * ensures (we hope) that ZeroTier traffic will still take the physical @@ -1807,6 +1906,23 @@ public: return 1; } + inline int nodePathLookupFunction(uint64_t ztaddr,int family,struct sockaddr_storage *result) + { + const Hashtable< uint64_t,std::vector > *lh = (const Hashtable< uint64_t,std::vector > *)0; + if (family < 0) + lh = (_node->prng() & 1) ? &_v4Hints : &_v6Hints; + else if (family == AF_INET) + lh = &_v4Hints; + else if (family == AF_INET6) + lh = &_v6Hints; + else return 0; + const std::vector *l = lh->get(ztaddr); + if ((l)&&(l->size() > 0)) { + memcpy(result,&((*l)[(unsigned long)_node->prng() % l->size()]),sizeof(struct sockaddr_storage)); + return 1; + } else return 0; + } + inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { _node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); @@ -1956,8 +2072,10 @@ static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct soc { return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast(uptr)->nodePathCheckFunction(localAddr,remoteAddr); } +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) +{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) +{ return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } #ifdef ZT_ENABLE_CLUSTER static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len) -- cgit v1.2.3 From 84732fcb12d66708e7887fba51413cbe629d86d3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 22 Nov 2016 14:23:13 -0800 Subject: Wire through external path lookup. Static paths should now work. --- node/Constants.hpp | 5 +++++ node/Node.cpp | 2 +- node/Node.hpp | 7 +++++-- node/Peer.cpp | 11 +++++++++++ node/Peer.hpp | 8 ++++++++ node/Switch.cpp | 15 ++++++++------- service/OneService.cpp | 13 +++++++------ 7 files changed, 45 insertions(+), 16 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 8803ecee..ac1919b3 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -320,6 +320,11 @@ */ #define ZT_MIN_UNITE_INTERVAL 30000 +/** + * How often should peers try memorized or statically defined paths? + */ +#define ZT_TRY_MEMORIZED_PATH_INTERVAL 30000 + /** * Sanity limit on maximum bridge routes * diff --git a/node/Node.cpp b/node/Node.cpp index a180766b..11f76365 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -683,7 +683,7 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) uint64_t Node::prng() { - unsigned int p = (++_prngStreamPtr % (sizeof(_prngStream) / sizeof(uint64_t))); + unsigned int p = (++_prngStreamPtr % ZT_NODE_PRNG_BUF_SIZE); if (!p) _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); return _prngStream[p]; diff --git a/node/Node.hpp b/node/Node.hpp index 7d99ff09..eb46527d 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -49,6 +49,9 @@ #define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 #define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 +// Size of PRNG stream buffer +#define ZT_NODE_PRNG_BUF_SIZE 64 + namespace ZeroTier { /** @@ -195,7 +198,7 @@ public: #endif bool shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); - inline bool getPathHint(const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } + inline bool externalPathLookup(const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); void postCircuitTestReport(const ZT_CircuitTestReport *report); @@ -284,7 +287,7 @@ private: unsigned int _prngStreamPtr; Salsa20 _prng; - uint64_t _prngStream[16]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream + uint64_t _prngStream[ZT_NODE_PRNG_BUF_SIZE]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream uint64_t _now; uint64_t _lastPingCheck; diff --git a/node/Peer.cpp b/node/Peer.cpp index e0bd0eac..2ef139e1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -43,6 +43,7 @@ static uint32_t _natKeepaliveBuf = 0; Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : _lastReceive(0), _lastNontrivialReceive(0), + _lastTriedMemorizedPath(0), _lastDirectPathPushSent(0), _lastDirectPathPushReceive(0), _lastCredentialRequestSent(0), @@ -373,6 +374,16 @@ void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &at } } +void Peer::tryMemorizedPath(uint64_t now) +{ + if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { + _lastTriedMemorizedPath = now; + InetAddress mp; + if (RR->node->externalPathLookup(_id.address(),-1,mp)) + attemptToContactAt(InetAddress(),mp,now); + } +} + bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); diff --git a/node/Peer.hpp b/node/Peer.hpp index a7240cb4..78b345b9 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -164,6 +164,13 @@ public: */ void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + /** + * Try a memorized or statically defined path if any are known + * + * Under the hood this is done periodically based on ZT_TRY_MEMORIZED_PATH_INTERVAL. + */ + void tryMemorizedPath(uint64_t now); + /** * Send pings or keepalives depending on configured timeouts * @@ -435,6 +442,7 @@ private: uint8_t _remoteClusterOptimal6[16]; uint64_t _lastReceive; // direct or indirect uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. + uint64_t _lastTriedMemorizedPath; uint64_t _lastDirectPathPushSent; uint64_t _lastDirectPathPushReceive; uint64_t _lastCredentialRequestSent; diff --git a/node/Switch.cpp b/node/Switch.cpp index 881d7b92..7c94d438 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -710,12 +710,12 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) if (peer) { const uint64_t now = RR->node->now(); - // First get the best path, and if it's dead (and this is not a root) - // we attempt to re-activate that path but this packet will flow - // upstream. If the path comes back alive, it will be used in the future. - // For roots we don't do the alive check since roots are not required - // to send heartbeats "down" and because we have to at least try to - // go somewhere. + /* First get the best path, and if it's dead (and this is not a root) + * we attempt to re-activate that path but this packet will flow + * upstream. If the path comes back alive, it will be used in the future. + * For roots we don't do the alive check since roots are not required + * to send heartbeats "down" and because we have to at least try to + * go somewhere. */ SharedPtr viaPath(peer->getBestPath(now,false)); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) { @@ -724,7 +724,8 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) viaPath.zero(); } if (!viaPath) { - SharedPtr relay(RR->topology->getUpstreamPeer()); + peer->tryMemorizedPath(now); // periodically attempt memorized or statically defined paths, if any are known + const SharedPtr relay(RR->topology->getUpstreamPeer()); if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { if (!(viaPath = peer->getBestPath(now,true))) return false; diff --git a/service/OneService.cpp b/service/OneService.cpp index 7434ca67..a2024e52 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1163,6 +1163,7 @@ public: // Internal implementation methods ----------------------------------------- + // Must be called after _localConfig is read or modified void applyLocalConfig() { Mutex::Lock _l(_localConfig_m); @@ -1872,6 +1873,12 @@ public: } } + /* Note: I do not think we need to scan for overlap with managed routes + * because of the "route forking" and interface binding that we do. This + * ensures (we hope) that ZeroTier traffic will still take the physical + * path even if its managed routes override this for other traffic. Will + * revisit if we see recursion problems. */ + // Check blacklists const Hashtable< uint64_t,std::vector > *blh = (const Hashtable< uint64_t,std::vector > *)0; const std::vector *gbl = (const std::vector *)0; @@ -1897,12 +1904,6 @@ public: } } - /* Note: I do not think we need to scan for overlap with managed routes - * because of the "route forking" and interface binding that we do. This - * ensures (we hope) that ZeroTier traffic will still take the physical - * path even if its managed routes override this for other traffic. Will - * revisit if we see problems with this. */ - return 1; } -- cgit v1.2.3 From 64774d0d4f552b2864abd969c6bc69c0ced3b2e1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 13:27:52 -0800 Subject: Replace piecemeal designation of upstreams with the concept of moons, which is simpler and easier to use and inherits all the cool live update stuff of worlds (now called planets) and global roots. --- include/ZeroTierOne.h | 15 +--- node/IncomingPacket.cpp | 22 ++--- node/Node.cpp | 85 ++++++-------------- node/Node.hpp | 1 - node/Peer.cpp | 12 +-- node/Switch.cpp | 2 +- node/Topology.cpp | 207 +++++++++++++++++++++++------------------------- node/Topology.hpp | 79 ++++++++++-------- node/World.hpp | 87 ++++++++++---------- service/OneService.cpp | 22 +++-- service/README.md | 1 - world/mkworld.cpp | 5 +- 12 files changed, 242 insertions(+), 296 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 8b1ee0ac..f0235b9d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -848,8 +848,8 @@ enum ZT_VirtualNetworkConfigOperation enum ZT_PeerRole { ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_UPSTREAM = 1, // upstream node - ZT_PEER_ROLE_ROOT = 2 // global root + ZT_PEER_ROLE_UPSTREAM = 1, // moon root + ZT_PEER_ROLE_ROOT = 2 // planetary root }; /** @@ -1903,17 +1903,6 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); */ int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); -/** - * Set peer role - * - * Right now this can only be used to set a peer to either LEAF or - * UPSTREAM, since roots are fixed and defined by the World. - * - * @param ztAddress ZeroTier address (least significant 40 bits) - * @param role New peer role (LEAF or UPSTREAM) - */ -void ZT_Node_setRole(ZT_Node *node,uint64_t ztAddress,enum ZT_PeerRole role); - /** * Set a network configuration master instance for this node * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 562aee91..2487a8aa 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -214,8 +214,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut Identity id; InetAddress externalSurfaceAddress; - uint64_t worldId = ZT_WORLD_ID_NULL; - uint64_t worldTimestamp = 0; + uint64_t planetWorldId = 0; + uint64_t planetWorldTimestamp = 0; { unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); @@ -223,10 +223,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Get world ID and world timestamp if present (was not in old versions) + // Get primary planet world ID and world timestamp if present if ((ptr + 16) <= size()) { - worldId = at(ptr); ptr += 8; - worldTimestamp = at(ptr); + planetWorldId = at(ptr); ptr += 8; + planetWorldTimestamp = at(ptr); } } @@ -356,14 +356,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut tmpa.serialize(outp); } - if ((worldId != ZT_WORLD_ID_NULL)&&(RR->topology->worldTimestamp() > worldTimestamp)&&(worldId == RR->topology->worldId())) { - World w(RR->topology->world()); + if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { + World w(RR->topology->planet()); const unsigned int sizeAt = outp.size(); outp.addSize(2); // make room for 16-bit size field w.serialize(outp,false); outp.setAt(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); } else { - outp.append((uint16_t)0); // no world update needed + outp.append((uint16_t)0); // no planet update needed } outp.armor(peer->key(),true); @@ -411,14 +411,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Handle world updates from root servers if present (was not on old versions) - if (((ptr + 2) <= size())&&(RR->topology->isRoot(peer->identity()))) { + // Handle planet or moon updates + if ((ptr + 2) <= size()) { World worldUpdate; const unsigned int worldLen = at(ptr); ptr += 2; if (worldLen > 0) { World w; w.deserialize(*this,ptr); - RR->topology->worldUpdateIfValid(w); + RR->topology->addWorld(w,true); } } diff --git a/node/Node.cpp b/node/Node.cpp index 0d0750ca..df22e3f2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -160,75 +160,48 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,const std::vector
&upstreams,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now) : lastReceiveFromUpstream(0), RR(renv), - _upstreams(upstreams), - _now(now), - _world(RR->topology->world()) + _now(now) { + RR->topology->getUpstreamStableEndpoints(_upstreams); } uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay inline void operator()(Topology &t,const SharedPtr &p) { - if (std::find(_upstreams.begin(),_upstreams.end(),p->address()) != _upstreams.end()) { - InetAddress stableEndpoint4,stableEndpoint6; - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - if (r->identity == p->identity()) { - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)r->stableEndpoints.size();++k) { - const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()]; - if (!stableEndpoint4) { - if (addr.ss_family == AF_INET) - stableEndpoint4 = addr; - } - if (!stableEndpoint6) { - if (addr.ss_family == AF_INET6) - stableEndpoint6 = addr; - } + const std::vector *upstreamStableEndpoints = _upstreams.get(p->address()); + if ((upstreamStableEndpoints)&&(upstreamStableEndpoints->size() > 0)) { + if (!p->doPingAndKeepalive(_now,AF_INET)) { + for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { + const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; + if (addr.ss_family == AF_INET) { + p->sendHELLO(InetAddress(),addr,_now); + break; } - break; } } - - // We keep connections to upstream peers alive forever. - bool needToContactIndirect = true; - if (p->doPingAndKeepalive(_now,AF_INET)) { - needToContactIndirect = false; - } else { - if (stableEndpoint4) { - needToContactIndirect = false; - p->sendHELLO(InetAddress(),stableEndpoint4,_now); - } - } - if (p->doPingAndKeepalive(_now,AF_INET6)) { - needToContactIndirect = false; - } else { - if (stableEndpoint6) { - needToContactIndirect = false; - p->sendHELLO(InetAddress(),stableEndpoint6,_now); + if (!p->doPingAndKeepalive(_now,AF_INET6)) { + for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { + const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; + if (addr.ss_family == AF_INET6) { + p->sendHELLO(InetAddress(),addr,_now); + break; + } } } - - // If we don't have a direct path or a static endpoint, send something indirectly to find one. - if (needToContactIndirect) { - Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP); - RR->sw->send(outp,true); - } - lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } else if (p->isActive(_now)) { - // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently p->doPingAndKeepalive(_now,-1); } } private: const RuntimeEnvironment *RR; - const std::vector
&_upstreams; uint64_t _now; - World _world; + Hashtable< Address,std::vector > _upstreams; }; ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) @@ -263,7 +236,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB } // Do pings and keepalives - _PingPeersThatNeedPing pfunc(RR,upstreams,now); + _PingPeersThatNeedPing pfunc(RR,now); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); // Update online status, post status change as event @@ -368,8 +341,8 @@ uint64_t Node::address() const void Node::status(ZT_NodeStatus *status) const { status->address = RR->identity.address().toInt(); - status->worldId = RR->topology->worldId(); - status->worldTimestamp = RR->topology->worldTimestamp(); + status->worldId = RR->topology->planetWorldId(); + status->worldTimestamp = RR->topology->planetWorldTimestamp(); status->publicIdentity = RR->publicIdentityStr.c_str(); status->secretIdentity = RR->secretIdentityStr.c_str(); status->relayPolicy = _relayPolicy; @@ -401,7 +374,7 @@ ZT_PeerList *Node::peers() const p->versionRev = -1; } p->latency = pi->second->latency(); - p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : (RR->topology->isUpstream(pi->second->identity()) ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); + p->role = RR->topology->role(pi->second->identity().address()); std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); SharedPtr bestp(pi->second->getBestPath(_now,false)); @@ -488,11 +461,6 @@ int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigne return 0; } -void Node::setRole(uint64_t ztAddress,ZT_PeerRole role) -{ - RR->topology->setUpstream(Address(ztAddress),(role == ZT_PEER_ROLE_UPSTREAM)); -} - void Node::setNetconfMaster(void *networkControllerInstance) { RR->localNetworkController = reinterpret_cast(networkControllerInstance); @@ -1016,13 +984,6 @@ int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const vo } } -void ZT_Node_setRole(ZT_Node *node,uint64_t ztAddress,ZT_PeerRole role) -{ - try { - reinterpret_cast(node)->setRole(ztAddress,role); - } catch ( ... ) {} -} - void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) { try { diff --git a/node/Node.hpp b/node/Node.hpp index d7b039b8..4c070014 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -105,7 +105,6 @@ public: int addLocalInterfaceAddress(const struct sockaddr_storage *addr); void clearLocalInterfaceAddresses(); int sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len); - void setRole(uint64_t ztAddress,ZT_PeerRole role); void setNetconfMaster(void *networkControllerInstance); ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); void circuitTestEnd(ZT_CircuitTest *test); diff --git a/node/Peer.cpp b/node/Peer.cpp index 2ef139e1..40356034 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -37,9 +37,6 @@ namespace ZeroTier { -// Used to send varying values for NAT keepalive -static uint32_t _natKeepaliveBuf = 0; - Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : _lastReceive(0), _lastNontrivialReceive(0), @@ -355,8 +352,8 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append(now); RR->identity.serialize(outp,false); atAddress.serialize(outp); - outp.append((uint64_t)RR->topology->worldId()); - outp.append((uint64_t)RR->topology->worldTimestamp()); + outp.append((uint64_t)RR->topology->planetWorldId()); + outp.append((uint64_t)RR->topology->planetWorldTimestamp()); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); @@ -401,12 +398,9 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) } if (bestp >= 0) { - if ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) { + if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); _paths[bestp].path->sent(now); - } else if (_paths[bestp].path->needsHeartbeat(now)) { - _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads - _paths[bestp].path->send(RR,&_natKeepaliveBuf,sizeof(_natKeepaliveBuf),now); } return true; } else { diff --git a/node/Switch.cpp b/node/Switch.cpp index 7c94d438..04624f03 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -718,7 +718,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) * go somewhere. */ SharedPtr viaPath(peer->getBestPath(now,false)); - if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isRoot(peer->identity())) ) { + if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now); viaPath.zero(); diff --git a/node/Topology.cpp b/node/Topology.cpp index bf51b585..be6807da 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -48,33 +48,22 @@ Topology::Topology(const RuntimeEnvironment *renv) : _trustedPathCount(0), _amRoot(false) { - // Get cached world if present - std::string dsWorld(RR->node->dataStoreGet("world")); - World cachedWorld; - if (dsWorld.length() > 0) { - try { - Buffer dswtmp(dsWorld.data(),(unsigned int)dsWorld.length()); - cachedWorld.deserialize(dswtmp,0); - } catch ( ... ) { - cachedWorld = World(); // clear if cached world is invalid - } - } - - // Use default or cached world depending on which is shinier - World defaultWorld; + World defaultPlanet; { Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top } - if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) { - _setWorld(defaultWorld); - if (dsWorld.length() > 0) - RR->node->dataStoreDelete("world"); - } else _setWorld(cachedWorld); -} + addWorld(defaultPlanet,false); -Topology::~Topology() -{ + try { + World cachedPlanet; + std::string buf(RR->node->dataStoreGet("planet")); + if (buf.length() > 0) { + Buffer dswtmp(buf.data(),(unsigned int)buf.length()); + cachedPlanet.deserialize(dswtmp,0); + } + addWorld(cachedPlanet,false); + } catch ( ... ) {} } SharedPtr Topology::addPeer(const SharedPtr &peer) @@ -161,15 +150,14 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi Mutex::Lock _l(_lock); if (_amRoot) { - /* If I am a root server, the "best" root server is the one whose address - * is numerically greater than mine (with wrap at top of list). This - * causes packets searching for a route to pretty much literally - * circumnavigate the globe rather than bouncing between just two. */ - - for(unsigned long p=0;p<_rootAddresses.size();++p) { - if (_rootAddresses[p] == RR->identity.address()) { - for(unsigned long q=1;q<_rootAddresses.size();++q) { - const SharedPtr *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]); + /* If I am a root, pick another root that isn't mine and that + * has a numerically greater ID. This causes packets to roam + * around the top rather than bouncing between just two. */ + + for(unsigned long p=0;p<_upstreamAddresses.size();++p) { + if (_upstreamAddresses[p] == RR->identity.address()) { + for(unsigned long q=1;q<_upstreamAddresses.size();++q) { + const SharedPtr *const nextsn = _peers.get(_upstreamAddresses[(p + q) % _upstreamAddresses.size()]); if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) return *nextsn; } @@ -178,8 +166,7 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi } } else { - /* Otherwise pick the best upstream from among roots and any other - * designated upstreams that we trust. */ + /* Otherwise pick the bestest looking upstream */ unsigned int bestQualityOverall = ~((unsigned int)0); unsigned int bestQualityNotAvoid = ~((unsigned int)0); @@ -219,82 +206,112 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi return SharedPtr(); } -bool Topology::isRoot(const Identity &id) const -{ - Mutex::Lock _l(_lock); - return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()); -} - bool Topology::isUpstream(const Identity &id) const { Mutex::Lock _l(_lock); return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); } -void Topology::setUpstream(const Address &a,bool upstream) +ZT_PeerRole Topology::role(const Address &ztaddr) const { - bool needWhois = false; - { - Mutex::Lock _l(_lock); - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),a) == _rootAddresses.end()) { - if (upstream) { - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),a) == _upstreamAddresses.end()) { - _upstreamAddresses.push_back(a); - const SharedPtr *p = _peers.get(a); - if (!p) { - const Identity id(_getIdentity(a)); - if (id) { - _peers.set(a,SharedPtr(new Peer(RR,RR->identity,id))); - } else { - needWhois = true; // need to do this later due to _lock - } - } - } - } else { - std::vector
ua; - for(std::vector
::iterator i(_upstreamAddresses.begin());i!=_upstreamAddresses.end();++i) { - if (a != *i) - ua.push_back(*i); - } - _upstreamAddresses.swap(ua); - } + Mutex::Lock _l(_lock); + if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + if (i->identity.address() == ztaddr) + return ZT_PEER_ROLE_ROOT; } + return ZT_PEER_ROLE_UPSTREAM; } - if (needWhois) - RR->sw->requestWhois(a); + return ZT_PEER_ROLE_LEAF; } bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const { Mutex::Lock _l(_lock); - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),ztaddr) != _rootAddresses.end()) { - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + // For roots the only permitted addresses are those defined. This adds just a little + // bit of extra security against spoofing, replaying, etc. + if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { + for(std::vector::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) { for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { if (ipaddr.ipsEqual(*e)) return false; } } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator r(m->roots().begin());r!=m->roots().end();++r) { + for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { + if (ipaddr.ipsEqual(*e)) + return false; + } + } + } return true; } return false; } -bool Topology::worldUpdateIfValid(const World &newWorld) +bool Topology::addWorld(const World &newWorld,bool updateOnly) { + if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) + return false; + Mutex::Lock _l(_lock); - if (_world.shouldBeReplacedBy(newWorld,true)) { - _setWorld(newWorld); - try { - Buffer dswtmp; - newWorld.serialize(dswtmp,false); - RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false); - } catch ( ... ) { - RR->node->dataStoreDelete("world"); + + World *existing = (World *)0; + switch(newWorld.type()) { + case World::TYPE_PLANET: + existing = &_planet; + break; + case World::TYPE_MOON: + for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) { + if (m->id() == newWorld.id()) { + existing = &(*m); + break; + } + } + break; + default: + return false; + } + + if (existing) { + if (existing->shouldBeReplacedBy(newWorld)) + *existing = newWorld; + else return false; + } else if ((newWorld.type() == World::TYPE_MOON)&&(!updateOnly)) { + _moons.push_back(newWorld); + existing = &(_moons.back()); + } else return false; + + char savePath[64]; + if (existing->type() == World::TYPE_MOON) + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx",existing->id()); + else Utils::scopy(savePath,sizeof(savePath),"planet"); + try { + Buffer dswtmp; + existing->serialize(dswtmp,false); + RR->node->dataStorePut(savePath,dswtmp.data(),dswtmp.size(),false); + } catch ( ... ) { + RR->node->dataStoreDelete(savePath); + } + + _upstreamAddresses.clear(); + _amRoot = false; + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + if (i->identity == RR->identity) + _amRoot = true; + else _upstreamAddresses.push_back(i->identity.address()); + } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + if (i->identity == RR->identity) + _amRoot = true; + else _upstreamAddresses.push_back(i->identity.address()); } - return true; } + return false; } @@ -334,34 +351,4 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } -void Topology::_setWorld(const World &newWorld) -{ - // assumed _lock is locked (or in constructor) - - std::vector
ua; - for(std::vector
::iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) - ua.push_back(*a); - } - - _world = newWorld; - _rootAddresses.clear(); - _amRoot = false; - - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - _rootAddresses.push_back(r->identity.address()); - if (std::find(ua.begin(),ua.end(),r->identity.address()) == ua.end()) - ua.push_back(r->identity.address()); - if (r->identity.address() == RR->identity.address()) { - _amRoot = true; - } else { - SharedPtr *rp = _peers.get(r->identity.address()); - if (!rp) - _peers.set(r->identity.address(),SharedPtr(new Peer(RR,RR->identity,r->identity))); - } - } - - _upstreamAddresses.swap(ua); -} - } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 90ad7083..47981248 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -50,7 +50,6 @@ class Topology { public: Topology(const RuntimeEnvironment *renv); - ~Topology(); /** * Add a peer to database @@ -141,12 +140,6 @@ public: */ SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); - /** - * @param id Identity to check - * @return True if this is a designated root server in this world - */ - bool isRoot(const Identity &id) const; - /** * @param id Identity to check * @return True if this is a root server or a network preferred relay from one of our networks @@ -154,14 +147,10 @@ public: bool isUpstream(const Identity &id) const; /** - * Set whether or not an address is upstream - * - * If the address is a root this does nothing, since roots are fixed. - * - * @param a Target address - * @param upstream New upstream status + * @param ztaddr ZeroTier address + * @return Peer role for this device */ - void setUpstream(const Address &a,bool upstream); + ZT_PeerRole role(const Address &ztaddr) const; /** * Check for prohibited endpoints @@ -179,6 +168,30 @@ public: */ bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; + /** + * @param eps Hash table to fill with addresses and their stable endpoints + */ + inline void getUpstreamStableEndpoints(Hashtable< Address,std::vector > &eps) const + { + Mutex::Lock _l(_lock); + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + std::vector &ips = eps[i->identity.address()]; + for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { + if (std::find(ips.begin(),ips.end(),*j) == ips.end()) + ips.push_back(*j); + } + } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + std::vector &ips = eps[i->identity.address()]; + for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { + if (std::find(ips.begin(),ips.end(),*j) == ips.end()) + ips.push_back(*j); + } + } + } + } + /** * @return Vector of active upstream addresses (including roots) */ @@ -189,37 +202,38 @@ public: } /** - * @return Current World (copy) + * @return Current planet */ - inline World world() const + inline World planet() const { Mutex::Lock _l(_lock); - return _world; + return _planet; } /** - * @return Current world ID + * @return Current planet's world ID */ - inline uint64_t worldId() const + inline uint64_t planetWorldId() const { - return _world.id(); // safe to read without lock, and used from within eachPeer() so don't lock + return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock } /** - * @return Current world timestamp + * @return Current planet's world timestamp */ - inline uint64_t worldTimestamp() const + inline uint64_t planetWorldTimestamp() const { - return _world.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock + return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock } /** * Validate new world and update if newer and signature is okay * - * @param newWorld Potential new world definition revision - * @return True if an update actually occurred + * @param newWorld A new or updated planet or moon to learn + * @param updateOnly If true only update currently known worlds + * @return True if it was valid and newer than current (or totally new for moons) */ - bool worldUpdateIfValid(const World &newWorld); + bool addWorld(const World &newWorld,bool updateOnly); /** * Clean and flush database @@ -284,9 +298,9 @@ public: } /** - * @return True if I am a root server in the current World + * @return True if I am a root server in a planet or moon */ - inline bool amRoot() const throw() { return _amRoot; } + inline bool amRoot() const { return _amRoot; } /** * Get the outbound trusted path ID for a physical address, or 0 if none @@ -339,7 +353,6 @@ public: private: Identity _getIdentity(const Address &zta); - void _setWorld(const World &newWorld); const RuntimeEnvironment *const RR; @@ -347,14 +360,14 @@ private: InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; unsigned int _trustedPathCount; - World _world; + World _planet; + std::vector< World > _moons; Hashtable< Address,SharedPtr > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - std::vector< Address > _upstreamAddresses; // includes roots - std::vector< Address > _rootAddresses; // only roots - bool _amRoot; // am I a root? + std::vector< Address > _upstreamAddresses; // includes root addresses of both planets and moons + bool _amRoot; // am I a root in a planet or moon? Mutex _lock; }; diff --git a/node/World.hpp b/node/World.hpp index 2f1edb00..c4682a69 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -48,16 +48,6 @@ */ #define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128) -/** - * World ID indicating null / empty World object - */ -#define ZT_WORLD_ID_NULL 0 - -/** - * World ID for a test network with ephemeral or temporary roots - */ -#define ZT_WORLD_ID_TESTNET 1 - /** * World ID for Earth * @@ -90,15 +80,23 @@ namespace ZeroTier { * orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A * world ID for Mars and nearby space is defined but not yet used, and a test * world ID is provided for testing purposes. - * - * If you absolutely must run your own "unofficial" ZeroTier network, please - * define your world IDs above 0xffffffff (4294967295). Code to make a World - * is in mkworld.cpp in the parent directory and must be edited to change - * settings. */ class World { public: + /** + * World type -- do not change IDs + */ + enum Type + { + TYPE_NULL = 0, + TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) + TYPE_MOON = 127 // Moons, which are user-created and many + }; + + /** + * Upstream server definition in world/moon + */ struct Root { Identity identity; @@ -113,45 +111,44 @@ public: * Construct an empty / null World */ World() : - _id(ZT_WORLD_ID_NULL), - _ts(0) {} + _id(0), + _ts(0), + _type(TYPE_NULL) {} /** * @return Root servers for this world and their stable endpoints */ - inline const std::vector &roots() const throw() { return _roots; } + inline const std::vector &roots() const { return _roots; } + + /** + * @return World type: planet or moon + */ + inline Type type() const { return _type; } /** * @return World unique identifier */ - inline uint64_t id() const throw() { return _id; } + inline uint64_t id() const { return _id; } /** * @return World definition timestamp */ - inline uint64_t timestamp() const throw() { return _ts; } + inline uint64_t timestamp() const { return _ts; } /** * Check whether a world update should replace this one * - * A new world update is valid if it is for the same world ID, is newer, - * and is signed by the current world's signing key. If this world object - * is null, it can always be updated. - * * @param update Candidate update - * @param fullSignatureCheck Perform full cryptographic signature check (true == yes, false == skip) - * @return True if update is newer than current and is properly signed + * @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL) */ - inline bool shouldBeReplacedBy(const World &update,bool fullSignatureCheck) + inline bool shouldBeReplacedBy(const World &update) { - if (_id == ZT_WORLD_ID_NULL) + if ((_id == 0)||(_type == TYPE_NULL)) return true; - if ((_id == update._id)&&(_ts < update._ts)) { - if (fullSignatureCheck) { - Buffer tmp; - update.serialize(tmp,true); - return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); - } else return true; + if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) { + Buffer tmp; + update.serialize(tmp,true); + return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); } return false; } @@ -159,14 +156,14 @@ public: /** * @return True if this World is non-empty */ - inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); } + inline operator bool() const { return (_type != TYPE_NULL); } template inline void serialize(Buffer &b,bool forSign = false) const { if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - b.append((uint8_t)0x01); + b.append((uint8_t)_type); b.append((uint64_t)_id); b.append((uint64_t)_ts); b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); @@ -190,14 +187,19 @@ public: _roots.clear(); - if (b[p++] != 0x01) - throw std::invalid_argument("invalid object type"); + switch((Type)b[p++]) { + case TYPE_NULL: _type = TYPE_NULL; break; // shouldn't ever really happen in serialized data but it's not invalid + case TYPE_PLANET: _type = TYPE_PLANET; break; + case TYPE_MOON: _type = TYPE_MOON; break; + default: + throw std::invalid_argument("invalid world type"); + } _id = b.template at(p); p += 8; _ts = b.template at(p); p += 8; memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN; memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - unsigned int numRoots = b[p++]; + const unsigned int numRoots = (unsigned int)b[p++]; if (numRoots > ZT_WORLD_MAX_ROOTS) throw std::invalid_argument("too many roots in World"); for(unsigned int k=0;k _roots; diff --git a/service/OneService.cpp b/service/OneService.cpp index 2932c605..6d9effa1 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -422,7 +422,7 @@ public: try { std::string authToken; { - std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S + "authtoken.secret"); + std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S "authtoken.secret"); if (!OSUtils::readFile(authTokenPath.c_str(),authToken)) { unsigned char foo[24]; Utils::getSecureRandom(foo,sizeof(foo)); @@ -442,7 +442,8 @@ public: authToken = _trimString(authToken); // Clean up any legacy files if present - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + "peers.save").c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S "peers.save").c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S "world").c_str()); { struct ZT_Node_Callbacks cb; @@ -465,7 +466,7 @@ public: unsigned int trustedPathCount = 0; // Old style "trustedpaths" flat file -- will eventually go away - FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S + "trustedpaths").c_str(),"r"); + FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(),"r"); if (trustpaths) { char buf[1024]; while ((fgets(buf,sizeof(buf),trustpaths))&&(trustedPathCount < ZT_MAX_TRUSTED_PATHS)) { @@ -493,7 +494,7 @@ public: // Read local config file Mutex::Lock _l2(_localConfig_m); std::string lcbuf; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + "local.conf").c_str(),lcbuf)) { + if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lcbuf)) { try { _localConfig = OSUtils::jsonParse(lcbuf); if (!_localConfig.is_object()) { @@ -581,7 +582,7 @@ public: // Write file containing primary port to be read by CLIs, etc. char portstr[64]; Utils::snprintf(portstr,sizeof(portstr),"%u",_ports[0]); - OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),std::string(portstr)); + OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S "zerotier-one.port").c_str(),std::string(portstr)); // Attempt to bind to a secondary port chosen from our ZeroTier address. // This exists because there are buggy NATs out there that fail if more @@ -641,8 +642,8 @@ public: _node->setNetconfMaster((void *)_controller); #ifdef ZT_ENABLE_CLUSTER - if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str())) { - _clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S + "cluster").c_str()); + if (OSUtils::fileExists((_homePath + ZT_PATH_SEPARATOR_S "cluster").c_str())) { + _clusterDefinition = new ClusterDefinition(_node->address(),(_homePath + ZT_PATH_SEPARATOR_S "cluster").c_str()); if (_clusterDefinition->size() > 0) { std::vector members(_clusterDefinition->members()); for(std::vector::iterator m(members.begin());m!=members.end();++m) { @@ -689,12 +690,12 @@ public: } #endif - _controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str()); + _controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S "ui").c_str()); _controlPlane->addAuthToken(authToken.c_str()); _controlPlane->setController(_controller); { // Remember networks from previous session - std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str())); + std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".conf")) @@ -919,9 +920,6 @@ public: if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { const Address ztaddr(nstr.c_str()); if (ztaddr) { - const std::string rstr(OSUtils::jsonString(v.value()["role"],"")); - _node->setRole(ztaddr.toInt(),((rstr == "upstream")||(rstr == "UPSTREAM")) ? ZT_PEER_ROLE_UPSTREAM : ZT_PEER_ROLE_LEAF); - const uint64_t ztaddr2 = ztaddr.toInt(); std::vector &v4h = _v4Hints[ztaddr2]; std::vector &v6h = _v6Hints[ztaddr2]; diff --git a/service/README.md b/service/README.md index d2398643..5d54b923 100644 --- a/service/README.md +++ b/service/README.md @@ -19,7 +19,6 @@ Settings available in `local.conf` (this is not valid JSON, and JSON does not al }, "virtual": { /* Settings applied to ZeroTier virtual network devices (VL1) */ "##########": { /* 10-digit ZeroTier address */ - "role": "upstream"|"leaf", /* If upstream, define this as a trusted "federated root" (default is leaf) */ "try": [ "IP/port"/*,...*/ ], /* Hints on where to reach this peer if no upstreams/roots are online */ "blacklist": [ "NETWORK/bits"/*,...*/ ] /* Blacklist a physical path for only this peer. */ } diff --git a/world/mkworld.cpp b/world/mkworld.cpp index 061d6341..2e9e621f 100644 --- a/world/mkworld.cpp +++ b/world/mkworld.cpp @@ -53,11 +53,12 @@ using namespace ZeroTier; class WorldMaker : public World { public: - static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) + static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) { WorldMaker w; w._id = id; w._ts = ts; + w._type = t; w._updateSigningKey = sk; w._roots = roots; @@ -139,7 +140,7 @@ int main(int argc,char **argv) fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); - World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP); + World nw = WorldMaker::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP); Buffer outtmp; nw.serialize(outtmp,false); -- cgit v1.2.3 From f102fd7f92225fbe39ae69dda716530a4e5457e9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 13:50:56 -0800 Subject: Extend in-band world updates to handle moons too. --- node/IncomingPacket.cpp | 40 ++++++++++++++++++++++++++++++---------- node/Packet.hpp | 13 +++++++++---- node/Peer.cpp | 11 +++++++++++ node/Topology.hpp | 9 +++++++++ node/World.hpp | 4 ++++ 5 files changed, 63 insertions(+), 14 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2487a8aa..1a60d13a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -216,6 +216,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut InetAddress externalSurfaceAddress; uint64_t planetWorldId = 0; uint64_t planetWorldTimestamp = 0; + std::vector< std::pair > moonIdsAndTimestamps; { unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); @@ -228,6 +229,16 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut planetWorldId = at(ptr); ptr += 8; planetWorldTimestamp = at(ptr); } + + // Get moon IDs and timestamps if present + if ((ptr + 2) <= size()) { + unsigned int numMoons = at(ptr); ptr += 2; + for(unsigned int i=0;i(at(ptr),at(ptr + 8))); + ptr += 16; + } + } } if (fromAddress != id.address()) { @@ -356,15 +367,24 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut tmpa.serialize(outp); } + const unsigned int worldUpdateSizeAt = outp.size(); + outp.addSize(2); // make room for 16-bit size field if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { - World w(RR->topology->planet()); - const unsigned int sizeAt = outp.size(); - outp.addSize(2); // make room for 16-bit size field - w.serialize(outp,false); - outp.setAt(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); - } else { - outp.append((uint16_t)0); // no planet update needed + RR->topology->planet().serialize(outp,false); + } + if (moonIdsAndTimestamps.size() > 0) { + std::vector moons(RR->topology->moons()); + for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { + for(std::vector< std::pair >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) { + if (i->first == m->id()) { + if (m->timestamp() > i->second) + m->serialize(outp,false); + break; + } + } + } } + outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),now); @@ -411,11 +431,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Handle planet or moon updates + // Handle planet or moon updates if present (older versions don't send this) if ((ptr + 2) <= size()) { - World worldUpdate; const unsigned int worldLen = at(ptr); ptr += 2; - if (worldLen > 0) { + const unsigned int endOfWorlds = ptr + worldLen; + while (ptr < endOfWorlds) { World w; w.deserialize(*this,ptr); RR->topology->addWorld(w,true); diff --git a/node/Packet.hpp b/node/Packet.hpp index 0be19f8a..26e87af8 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -536,12 +536,17 @@ public: * <[1] software major version> * <[1] software minor version> * <[2] software revision> - * <[8] timestamp (ms since epoch)> + * <[8] timestamp for determining latench> * <[...] binary serialized identity (see Identity)> * <[1] destination address type> * [<[...] destination address to which packet was sent>] - * <[8] 64-bit world ID of current world> - * <[8] 64-bit timestamp of current world> + * <[8] 64-bit world ID of current planet> + * <[8] 64-bit timestamp of current planet> + * <[2] 16-bit number of moons> + * [<[1] 8-bit type ID of moon>] + * [<[8] 64-bit world ID of moon>] + * [<[8] 64-bit timestamp of moon>] + * [... additional moons ...] * * This is the only message that ever must be sent in the clear, since it * is used to push an identity to a new peer. @@ -567,7 +572,7 @@ public: * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] * <[2] 16-bit length of world update or 0 if none> - * [[...] world update] + * [[...] updates to planets and/or moons] * * ERROR has no payload. */ diff --git a/node/Peer.cpp b/node/Peer.cpp index 40356034..441a5b33 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -345,6 +345,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); + outp.append((unsigned char)ZT_PROTO_VERSION); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); @@ -352,8 +353,18 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append(now); RR->identity.serialize(outp,false); atAddress.serialize(outp); + outp.append((uint64_t)RR->topology->planetWorldId()); outp.append((uint64_t)RR->topology->planetWorldTimestamp()); + + std::vector moons(RR->topology->moons()); + outp.append((uint16_t)moons.size()); + for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { + outp.append((uint8_t)m->type()); + outp.append((uint64_t)m->id()); + outp.append((uint64_t)m->timestamp()); + } + RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); diff --git a/node/Topology.hpp b/node/Topology.hpp index 47981248..6369c5cd 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -201,6 +201,15 @@ public: return _upstreamAddresses; } + /** + * @return Current moons + */ + inline std::vector moons() const + { + Mutex::Lock _l(_lock); + return _moons; + } + /** * @return Current planet */ diff --git a/node/World.hpp b/node/World.hpp index c4682a69..06dcb981 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -176,6 +176,8 @@ public: for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) ep->serialize(b); } + if (_type == TYPE_MOON) + b.append((uint16_t)0); // no attached dictionary (for future use) if (forSign) b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); } @@ -214,6 +216,8 @@ public: p += r.stableEndpoints.back().deserialize(b,p); } } + if (_type == TYPE_MOON) + p += b.template at(p) + 2; return (p - startAt); } -- cgit v1.2.3 From 9f7919f71f6b4326e73759923d2cf747affc0244 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 27 Jan 2017 15:27:26 -0800 Subject: Add comments to join ("orbit") moons. --- include/ZeroTierOne.h | 22 +++++++++ node/IncomingPacket.cpp | 3 +- node/Node.cpp | 49 ++++++++++++++++++-- node/Node.hpp | 2 + node/Peer.cpp | 9 +++- node/Topology.cpp | 120 ++++++++++++++++++++++++++++++++++++++++-------- node/Topology.hpp | 39 ++++++++++++++-- service/OneService.cpp | 8 ++++ 8 files changed, 222 insertions(+), 30 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index f75638f8..6c50a0a6 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1779,6 +1779,28 @@ enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64 */ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); +/** + * Add or update a moon + * + * Moons are persisted in the data store in moons.d/, so this can persist + * across invocations if the contents of moon.d are scanned and orbit is + * called for each on startup. + * + * @param moonWorldId Moon's world ID + * @param len Length of moonWorld in bytes + * @return Error if moon was invalid or failed to be added + */ +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId); + +/** + * Remove a moon (does nothing if not present) + * + * @param node Node instance + * @param moonWorldId World ID of moon to remove + * @return Error if anything bad happened + */ +ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId); + /** * Get this node's 40-bit ZeroTier address * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 28b845b4..93bf4590 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -444,7 +444,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); - peer->addDirectLatencyMeasurment(latency); + if (!hops()) + peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) diff --git a/node/Node.cpp b/node/Node.cpp index 23271cca..f5ee1f9d 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -168,26 +168,35 @@ public: inline void operator()(Topology &t,const SharedPtr &p) { - const std::vector *upstreamStableEndpoints = _upstreams.get(p->address()); - if ((upstreamStableEndpoints)&&(upstreamStableEndpoints->size() > 0)) { + const std::vector *const upstreamStableEndpoints = _upstreams.get(p->address()); + if (upstreamStableEndpoints) { + bool contacted = false; + if (!p->doPingAndKeepalive(_now,AF_INET)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { p->sendHELLO(InetAddress(),addr,_now); + contacted = true; break; } } - } + } else contacted = true; + if (!p->doPingAndKeepalive(_now,AF_INET6)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { p->sendHELLO(InetAddress(),addr,_now); + contacted = true; break; } } - } + } else contacted = true; + + if (!contacted) + p->sendHELLO(InetAddress(),InetAddress(),_now); + lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } else if (p->isActive(_now)) { p->doPingAndKeepalive(_now,-1); @@ -224,7 +233,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) (*n)->requestConfiguration(); - // Run WHOIS on upstreams we don't know about + // Attempt to get identity for any unknown upstreams const std::vector
upstreams(RR->topology->upstreamAddresses()); for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { if (!RR->topology->getPeer(*a)) @@ -323,6 +332,18 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } +ZT_ResultCode Node::orbit(uint64_t moonWorldId) +{ + RR->topology->addMoon(moonWorldId); + return ZT_RESULT_OK; +} + +ZT_ResultCode Node::deorbit(uint64_t moonWorldId) +{ + RR->topology->removeMoon(moonWorldId); + return ZT_RESULT_OK; +} + uint64_t Node::address() const { return RR->identity.address().toInt(); @@ -893,6 +914,24 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint } } +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId) +{ + try { + return reinterpret_cast(node)->orbit(moonWorldId); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId) +{ + try { + return reinterpret_cast(node)->deorbit(moonWorldId); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + uint64_t ZT_Node_address(ZT_Node *node) { return reinterpret_cast(node)->address(); diff --git a/node/Node.hpp b/node/Node.hpp index 662abcb4..3e742092 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -95,6 +95,8 @@ public: ZT_ResultCode leave(uint64_t nwid,void **uptr); ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); + ZT_ResultCode orbit(uint64_t moonWorldId); + ZT_ResultCode deorbit(uint64_t moonWorldId); uint64_t address() const; void status(ZT_NodeStatus *status) const; ZT_PeerList *peers() const; diff --git a/node/Peer.cpp b/node/Peer.cpp index 441a5b33..50135b9f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -366,8 +366,13 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u } RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,false); // HELLO is sent in the clear - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + + if (atAddress) { + outp.armor(_key,false); + RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + } else { + RR->sw->send(outp,false); + } } void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) diff --git a/node/Topology.cpp b/node/Topology.cpp index be6807da..38afacb0 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -48,13 +48,6 @@ Topology::Topology(const RuntimeEnvironment *renv) : _trustedPathCount(0), _amRoot(false) { - World defaultPlanet; - { - Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top - } - addWorld(defaultPlanet,false); - try { World cachedPlanet; std::string buf(RR->node->dataStoreGet("planet")); @@ -64,6 +57,13 @@ Topology::Topology(const RuntimeEnvironment *renv) : } addWorld(cachedPlanet,false); } catch ( ... ) {} + + World defaultPlanet; + { + Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); + defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + } + addWorld(defaultPlanet,false); } SharedPtr Topology::addPeer(const SharedPtr &peer) @@ -287,7 +287,7 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) char savePath[64]; if (existing->type() == World::TYPE_MOON) - Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx",existing->id()); + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",existing->id()); else Utils::scopy(savePath,sizeof(savePath),"planet"); try { Buffer dswtmp; @@ -297,22 +297,71 @@ bool Topology::addWorld(const World &newWorld,bool updateOnly) RR->node->dataStoreDelete(savePath); } - _upstreamAddresses.clear(); - _amRoot = false; - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity == RR->identity) - _amRoot = true; - else _upstreamAddresses.push_back(i->identity.address()); + if (existing->type() == World::TYPE_MOON) { + std::vector
cm; + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + if (m->toInt() != ((existing->id() >> 24) & 0xffffffffffULL)) + cm.push_back(*m); + } + _contacingMoons.swap(cm); } + + _memoizeUpstreams(); + + return true; +} + +void Topology::addMoon(const uint64_t id) +{ + char savePath[64]; + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); + + try { + std::string moonBin(RR->node->dataStoreGet(savePath)); + if (moonBin.length() > 1) { + Buffer wtmp(moonBin.data(),(unsigned int)moonBin.length()); + World w; + w.deserialize(wtmp); + if (w.type() == World::TYPE_MOON) { + addWorld(w,false); + return; + } + } + } catch ( ... ) {} + + { + const Address a(id >> 24); + Mutex::Lock _l(_lock); + if (std::find(_contacingMoons.begin(),_contacingMoons.end(),a) == _contacingMoons.end()) + _contacingMoons.push_back(a); + } + RR->node->dataStorePut(savePath,"\0",1,false); // persist that we want to be a member +} + +void Topology::removeMoon(const uint64_t id) +{ + Mutex::Lock _l(_lock); + + std::vector nm; for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity == RR->identity) - _amRoot = true; - else _upstreamAddresses.push_back(i->identity.address()); + if (m->id() != id) { + nm.push_back(*m); + } else { + char savePath[64]; + Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); + RR->node->dataStoreDelete(savePath); } } + _moons.swap(nm); - return false; + std::vector
cm; + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + if (m->toInt() != ((id >> 24) & 0xffffffffffULL)) + cm.push_back(*m); + } + _contacingMoons.swap(cm); + + _memoizeUpstreams(); } void Topology::clean(uint64_t now) @@ -351,4 +400,37 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } +void Topology::_memoizeUpstreams() +{ + // assumes _lock is locked + _upstreamAddresses.clear(); + _amRoot = false; + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { + if (i->identity == RR->identity) { + _amRoot = true; + } else { + _upstreamAddresses.push_back(i->identity.address()); + SharedPtr &hp = _peers[i->identity.address()]; + if (!hp) { + hp = new Peer(RR,RR->identity,i->identity); + saveIdentity(i->identity); + } + } + } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { + for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { + if (i->identity == RR->identity) { + _amRoot = true; + } else { + _upstreamAddresses.push_back(i->identity.address()); + SharedPtr &hp = _peers[i->identity.address()]; + if (!hp) { + hp = new Peer(RR,RR->identity,i->identity); + saveIdentity(i->identity); + } + } + } + } +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 6369c5cd..693ae12c 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -169,6 +169,11 @@ public: bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; /** + * This gets the known stable endpoints for any upstream + * + * It also adds empty entries for any upstreams we are attempting to + * contact. + * * @param eps Hash table to fill with addresses and their stable endpoints */ inline void getUpstreamStableEndpoints(Hashtable< Address,std::vector > &eps) const @@ -190,6 +195,8 @@ public: } } } + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) + eps[*m]; } /** @@ -198,7 +205,12 @@ public: inline std::vector
upstreamAddresses() const { Mutex::Lock _l(_lock); - return _upstreamAddresses; + std::vector
u(_upstreamAddresses); + for(std::vector
::const_iterator m(_contacingMoons.begin());m!=_contacingMoons.end();++m) { + if (std::find(u.begin(),u.end(),*m) == u.end()) + u.push_back(*m); + } + return u; } /** @@ -244,6 +256,25 @@ public: */ bool addWorld(const World &newWorld,bool updateOnly); + /** + * Add a moon + * + * This loads it from moons.d if present, and if not adds it to + * a list of moons that we want to contact. It does not actually + * send anything, though this will happen on the next background + * task loop where pings etc. are checked. + * + * @param id Moon ID + */ + void addMoon(const uint64_t id); + + /** + * Remove a moon + * + * @param id Moon's world ID + */ + void removeMoon(const uint64_t id); + /** * Clean and flush database */ @@ -362,6 +393,7 @@ public: private: Identity _getIdentity(const Address &zta); + void _memoizeUpstreams(); const RuntimeEnvironment *const RR; @@ -375,8 +407,9 @@ private: Hashtable< Address,SharedPtr > _peers; Hashtable< Path::HashKey,SharedPtr > _paths; - std::vector< Address > _upstreamAddresses; // includes root addresses of both planets and moons - bool _amRoot; // am I a root in a planet or moon? + std::vector
_contacingMoons; + std::vector
_upstreamAddresses; + bool _amRoot; Mutex _lock; }; diff --git a/service/OneService.cpp b/service/OneService.cpp index f6174d42..d2ebe6b7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -702,6 +702,14 @@ public: _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0); } } + { // Load existing moons + std::vector moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str())); + for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { + std::size_t dot = f->find_last_of('.'); + if ((dot == 16)&&(f->substr(16) == ".moon")) + _node->orbit(Utils::hexStrToU64(f->substr(0,dot).c_str())); + } + } _nextBackgroundTaskDeadline = 0; uint64_t clockShouldBe = OSUtils::now(); -- cgit v1.2.3 From dcb1233b0d5478f2f544a99cf24314155e711050 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 3 Feb 2017 23:54:02 -0800 Subject: Slight refactor to RENEDEZVOUS sending code for federation. --- node/Cluster.cpp | 4 +- node/Peer.cpp | 2 +- node/Peer.hpp | 2 +- node/Switch.cpp | 171 ++++++++++++++++++++++--------------------------------- node/Switch.hpp | 2 - 5 files changed, 72 insertions(+), 109 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 356a0887..00122402 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -400,7 +400,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) SharedPtr localPeer(RR->topology->getPeerNoCache(localPeerAddress)); if ((localPeer)&&(numRemotePeerPaths > 0)) { InetAddress bestLocalV4,bestLocalV6; - localPeer->getBestActiveAddresses(now,bestLocalV4,bestLocalV6); + localPeer->getRendezvousAddresses(now,bestLocalV4,bestLocalV6); InetAddress bestRemoteV4,bestRemoteV6; for(unsigned int i=0;i fromPeer(RR->topology->getPeerNoCache(fromPeerAddress)); if (fromPeer) - fromPeer->getBestActiveAddresses(now,v4,v6); + fromPeer->getRendezvousAddresses(now,v4,v6); } uint8_t addrCount = 0; if (v4) diff --git a/node/Peer.cpp b/node/Peer.cpp index 50135b9f..129c2437 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -446,7 +446,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin } } -void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const +void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const { Mutex::Lock _l(_paths_m); diff --git a/node/Peer.hpp b/node/Peer.hpp index 06abde3f..bbe13a2e 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -208,7 +208,7 @@ public: * @param v4 Result parameter to receive active IPv4 address, if any * @param v6 Result parameter to receive active IPv6 address, if any */ - void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; /** * @param now Current time diff --git a/node/Switch.cpp b/node/Switch.cpp index 2ab3ccfc..b53466cf 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -64,10 +64,6 @@ Switch::Switch(const RuntimeEnvironment *renv) : { } -Switch::~Switch() -{ -} - void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) { try { @@ -221,7 +217,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from if (packet.hops() < ZT_RELAY_MAX_HOPS) { #ifdef ZT_ENABLE_CLUSTER - if (source != RR->identity.address()) + if (source != RR->identity.address()) // don't increment hops for cluster frontplane relays packet.incrementHops(); #else packet.incrementHops(); @@ -229,13 +225,74 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from SharedPtr relayTo = RR->topology->getPeer(destination); if ((relayTo)&&((relayTo->sendDirect(packet.data(),packet.size(),now,false)))) { - if (source != RR->identity.address()) { - Mutex::Lock _l(_lastUniteAttempt_m); - uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)]; - if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) { - luts = now; - _unite(source,destination); + if (source != RR->identity.address()) { // don't send RENDEZVOUS for cluster frontplane relays + + bool shouldUnite; + { + Mutex::Lock _l(_lastUniteAttempt_m); + uint64_t &lastUniteAt = _lastUniteAttempt[_LastUniteKey(source,destination)]; + shouldUnite = ((now - lastUniteAt) >= ZT_MIN_UNITE_INTERVAL); + if (shouldUnite) + lastUniteAt = now; } + + if (shouldUnite) { + const InetAddress *hintToSource = (InetAddress *)0; + const InetAddress *hintToDest = (InetAddress *)0; + + InetAddress destV4,destV6; + InetAddress sourceV4,sourceV6; + relayTo->getRendezvousAddresses(now,destV4,destV6); + + const SharedPtr sourcePeer(RR->topology->getPeer(source)); + if (sourcePeer) { + sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6); + if ((destV6)&&(sourceV6)) { + hintToSource = &destV6; + hintToDest = &sourceV6; + } else if ((destV4)&&(sourceV4)) { + hintToSource = &destV4; + hintToDest = &sourceV4; + } + + if ((hintToSource)&&(hintToDest)) { + TRACE(">> RENDEZVOUS: %s(%s) <> %s(%s)",p1.toString().c_str(),p1a->toString().c_str(),p2.toString().c_str(),p2a->toString().c_str()); + unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for obscure NAT-t reasons + const unsigned int completed = alt + 2; + while (alt != completed) { + if ((alt & 1) == 0) { + Packet outp(source,RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + destination.appendTo(outp); + outp.append((uint16_t)hintToSource->port()); + if (hintToSource->ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(hintToSource->rawIpData(),16); + } else { + outp.append((uint8_t)4); + outp.append(hintToSource->rawIpData(),4); + } + send(outp,true); + } else { + Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + source.appendTo(outp); + outp.append((uint16_t)hintToDest->port()); + if (hintToDest->ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(hintToDest->rawIpData(),16); + } else { + outp.append((uint8_t)4); + outp.append(hintToDest->rawIpData(),4); + } + send(outp,true); + } + ++alt; + } + } + } + } + } } else { #ifdef ZT_ENABLE_CLUSTER @@ -824,96 +881,4 @@ bool Switch::_trySend(Packet &packet,bool encrypt) return true; } -bool Switch::_unite(const Address &p1,const Address &p2) -{ - if ((p1 == RR->identity.address())||(p2 == RR->identity.address())) - return false; - - const uint64_t now = RR->node->now(); - InetAddress *p1a = (InetAddress *)0; - InetAddress *p2a = (InetAddress *)0; - InetAddress p1v4,p1v6,p2v4,p2v6,uv4,uv6; - { - const SharedPtr p1p(RR->topology->getPeer(p1)); - const SharedPtr p2p(RR->topology->getPeer(p2)); - if ((!p1p)&&(!p2p)) return false; - if (p1p) p1p->getBestActiveAddresses(now,p1v4,p1v6); - if (p2p) p2p->getBestActiveAddresses(now,p2v4,p2v6); - } - if ((p1v6)&&(p2v6)) { - p1a = &p1v6; - p2a = &p2v6; - } else if ((p1v4)&&(p2v4)) { - p1a = &p1v4; - p2a = &p2v4; - } else { - SharedPtr upstream(RR->topology->getUpstreamPeer()); - if (!upstream) - return false; - upstream->getBestActiveAddresses(now,uv4,uv6); - if ((p1v6)&&(uv6)) { - p1a = &p1v6; - p2a = &uv6; - } else if ((p1v4)&&(uv4)) { - p1a = &p1v4; - p2a = &uv4; - } else if ((p2v6)&&(uv6)) { - p1a = &p2v6; - p2a = &uv6; - } else if ((p2v4)&&(uv4)) { - p1a = &p2v4; - p2a = &uv4; - } else return false; - } - - TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),p1a->toString().c_str(),p2.toString().c_str(),p2a->toString().c_str()); - - /* Tell P1 where to find P2 and vice versa, sending the packets to P1 and - * P2 in randomized order in terms of which gets sent first. This is done - * since in a few cases NAT-t can be sensitive to slight timing differences - * in terms of when the two peers initiate. Normally this is accounted for - * by the nearly-simultaneous RENDEZVOUS kickoff from the relay, but - * given that relay are hosted on cloud providers this can in some - * cases have a few ms of latency between packet departures. By randomizing - * the order we make each attempted NAT-t favor one or the other going - * first, meaning if it doesn't succeed the first time it might the second - * and so forth. */ - unsigned int alt = (unsigned int)RR->node->prng() & 1; - const unsigned int completed = alt + 2; - while (alt != completed) { - if ((alt & 1) == 0) { - // Tell p1 where to find p2. - Packet outp(p1,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((unsigned char)0); - p2.appendTo(outp); - outp.append((uint16_t)p2a->port()); - if (p2a->isV6()) { - outp.append((unsigned char)16); - outp.append(p2a->rawIpData(),16); - } else { - outp.append((unsigned char)4); - outp.append(p2a->rawIpData(),4); - } - send(outp,true); - } else { - // Tell p2 where to find p1. - Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((unsigned char)0); - p1.appendTo(outp); - outp.append((uint16_t)p1a->port()); - if (p1a->isV6()) { - outp.append((unsigned char)16); - outp.append(p1a->rawIpData(),16); - } else { - outp.append((unsigned char)4); - outp.append(p1a->rawIpData(),4); - } - send(outp,true); - } - ++alt; // counts up and also flips LSB - } - - return true; -} - } // namespace ZeroTier diff --git a/node/Switch.hpp b/node/Switch.hpp index 422f6c8e..ce1c40b3 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -55,7 +55,6 @@ class Switch : NonCopyable { public: Switch(const RuntimeEnvironment *renv); - ~Switch(); /** * Called when a packet is received from the real network @@ -127,7 +126,6 @@ public: private: Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); bool _trySend(Packet &packet,bool encrypt); // packet is modified if return is true - bool _unite(const Address &p1,const Address &p2); const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; -- cgit v1.2.3 From 3587aa1ea7573198168422be55511b16470fb33f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sat, 4 Feb 2017 13:17:00 -0800 Subject: Add and send certificates of representation to tell people what our valid upstreams are. These are not used yet but will be needed for future privacy modes, etc. Also some cleanup. --- node/Capability.hpp | 9 +- node/CertificateOfRepresentation.hpp | 161 +++++++++++++++++++++++++++++++++++ node/Constants.hpp | 5 ++ node/IncomingPacket.cpp | 9 ++ node/Packet.hpp | 32 ++----- node/Peer.cpp | 7 +- node/Peer.hpp | 11 ++- node/Revocation.hpp | 2 + node/Tag.hpp | 14 +-- node/Topology.cpp | 11 +++ node/Topology.hpp | 21 +++++ 11 files changed, 247 insertions(+), 35 deletions(-) create mode 100644 node/CertificateOfRepresentation.hpp (limited to 'node/Peer.cpp') diff --git a/node/Capability.hpp b/node/Capability.hpp index 2c829ee5..ddbfd9ee 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -414,7 +414,14 @@ public: throw std::runtime_error("unterminated custody chain"); _custody[i].to = to; _custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + if (b[p++] == 1) { + if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) + throw std::runtime_error("invalid signature"); + p += 2; + memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + } else { + p += 2 + b.template at(p); + } } p += 2 + b.template at(p); diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp new file mode 100644 index 00000000..7c239a96 --- /dev/null +++ b/node/CertificateOfRepresentation.hpp @@ -0,0 +1,161 @@ +/* + * 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 . + */ + +#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP +#define ZT_CERTIFICATEOFREPRESENTATION_HPP + +#include "Constants.hpp" +#include "Address.hpp" +#include "C25519.hpp" +#include "Identity.hpp" +#include "Buffer.hpp" + +/** + * Maximum number of addresses allowed in a COR + */ +#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS + +namespace ZeroTier { + +class CertificateOfRepresentation +{ +public: + CertificateOfRepresentation() + { + memset(this,0,sizeof(CertificateOfRepresentation)); + } + + inline uint64_t timestamp() const { return _timestamp; } + inline const Address &representative(const unsigned int i) const { return _reps[i]; } + inline unsigned int repCount() const { return _repCount; } + + inline void clear() + { + memset(this,0,sizeof(CertificateOfRepresentation)); + } + + /** + * Add a representative if space remains + * + * @param r Representative to add + * @return True if representative was added + */ + inline bool addRepresentative(const Address &r) + { + if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) { + _reps[_repCount++] = r; + return true; + } + return false; + } + + /** + * Sign this COR with my identity + * + * @param myIdentity This node's identity + * @param ts COR timestamp for establishing new vs. old + */ + inline void sign(const Identity &myIdentity,const uint64_t ts) + { + _timestamp = ts; + Buffer tmp; + this->serialize(tmp,true); + _signature = myIdentity.sign(tmp.data(),tmp.size()); + } + + /** + * Verify this COR's signature + * + * @param senderIdentity Identity of sender of COR + * @return True if COR is valid + */ + inline bool verify(const Identity &senderIdentity) + { + try { + Buffer tmp; + this->serialize(tmp,true); + return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN); + } catch ( ... ) { + return false; + } + } + + template + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + b.append((uint64_t)_timestamp); + b.append((uint16_t)_repCount); + for(unsigned int i=0;i<_repCount;++i) + _reps[i].appendTo(b); + + if (!forSign) { + b.append((uint8_t)1); // 1 == Ed25519 signature + b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + } + + b.append((uint16_t)0); // size of any additional fields, currently 0 + + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + + template + inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) + { + clear(); + + unsigned int p = startAt; + + _timestamp = b.template at(p); p += 8; + const unsigned int rc = b.template at(p); p += 2; + for(unsigned int i=0;i ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc; + + if (b[p++] == 1) { + if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { + p += 2; + memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); + p += ZT_C25519_SIGNATURE_LEN; + } else throw std::runtime_error("invalid signature"); + } else { + p += 2 + b.template at(p); + } + + p += 2 + b.template at(p); + if (p > b.size()) + throw std::runtime_error("extended field overflow"); + + return (p - startAt); + } + +private: + uint64_t _timestamp; + Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES]; + unsigned int _repCount; + C25519::Signature _signature; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Constants.hpp b/node/Constants.hpp index ab6dfb32..be4eb475 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -226,6 +226,11 @@ */ #define ZT_RELAY_MAX_HOPS 3 +/** + * Maximum number of upstreams to use (far more than we should ever need) + */ +#define ZT_MAX_UPSTREAMS 64 + /** * Expire time for multicast 'likes' and indirect multicast memberships in ms */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index cecbe2fa..6b38c4ec 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -37,6 +37,7 @@ #include "Cluster.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" +#include "CertificateOfRepresentation.hpp" #include "Capability.hpp" #include "Tag.hpp" #include "Revocation.hpp" @@ -445,6 +446,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p } } + // Handle COR if present (older versions don't send this) + if ((ptr + 2) <= size()) { + //const unsigned int corSize = at(ptr); ptr += 2; + ptr += 2; + CertificateOfRepresentation cor; + ptr += cor.deserialize(*this,ptr); + } + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_path->address().toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)")); if (!hops()) diff --git a/node/Packet.hpp b/node/Packet.hpp index a5831c8d..7d404b25 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -531,7 +531,7 @@ public: VERB_NOP = 0x00, /** - * Announcement of a node's existence: + * Announcement of a node's existence and vitals: * <[1] protocol version> * <[1] software major version> * <[1] software minor version> @@ -547,10 +547,12 @@ public: * [<[8] 64-bit world ID of moon>] * [<[8] 64-bit timestamp of moon>] * [... additional moons ...] + * <[2] 16-bit length of certificate of representation> + * [... certificate of representation ...] * - * Important security note: this message is sent in the clear as it - * contains the initial identity for key agreement. It can therefore - * contain no secrets or sensitive information. + * HELLO is sent in the clear, and therefore cannot contain anything + * secret or highly confidential. It should contain nothing that is + * not either public or easy to obtain via other means. * * The destination address is the wire address to which this packet is * being sent, and in OK is *also* the destination address of the OK @@ -1059,27 +1061,7 @@ public: * ZeroTier, Inc. itself. We recommend making up random ones for your own * implementations. */ - VERB_USER_MESSAGE = 0x14, - - /** - * Announce that we can reach a particular address: - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[...] binary serialized identity (see Identity)> - * <[1] 8-bit number of direct addresses where peer is reachable (if any)> - * [... serialized direct addresses ...] - * - * This message can be sent upstream to announce that we can reach a - * particular address. It can optionally report physical paths upstream - * to allow upstream peers to send RENDEZVOUS, but this may be omitted - * if it is not known or if endpoint address privacy is desired. - * - * The receiving peer should confirm this message by sending a message - * downstream and waiting for a reply. - */ - VERB_CAN_REACH = 0x15 + VERB_USER_MESSAGE = 0x14 }; /** diff --git a/node/Peer.cpp b/node/Peer.cpp index 129c2437..bb6b945d 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -38,6 +38,7 @@ namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : + RR(renv), _lastReceive(0), _lastNontrivialReceive(0), _lastTriedMemorizedPath(0), @@ -50,7 +51,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), - RR(renv), _remoteClusterOptimal4(0), _vProto(0), _vMajor(0), @@ -365,6 +365,11 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append((uint64_t)m->timestamp()); } + const unsigned int corSizeAt = outp.size(); + outp.addSize(2); + RR->topology->appendCertificateOfRepresentation(outp); + outp.setAt(corSizeAt,(uint16_t)((outp.size() - corSizeAt) - 2)); + RR->node->expectReplyTo(outp.packetId()); if (atAddress) { diff --git a/node/Peer.hpp b/node/Peer.hpp index bbe13a2e..e79739a3 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -439,7 +439,9 @@ private: } uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; - uint8_t _remoteClusterOptimal6[16]; + + const RuntimeEnvironment *RR; + uint64_t _lastReceive; // direct or indirect uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. uint64_t _lastTriedMemorizedPath; @@ -452,13 +454,17 @@ private: uint64_t _lastComRequestSent; uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; - const RuntimeEnvironment *RR; + + uint8_t _remoteClusterOptimal6[16]; uint32_t _remoteClusterOptimal4; + uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; + Identity _id; + struct { uint64_t lastReceive; SharedPtr path; @@ -467,6 +473,7 @@ private: #endif } _paths[ZT_MAX_PEER_NETWORK_PATHS]; Mutex _paths_m; + unsigned int _numPaths; unsigned int _latency; unsigned int _directPathPushCutoffCount; diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 18916985..bc290e75 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -152,6 +152,8 @@ public: memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; } else throw std::runtime_error("invalid signature"); + } else { + p += 2 + b.template at(p); } p += 2 + b.template at(p); diff --git a/node/Tag.hpp b/node/Tag.hpp index 97228157..65348200 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -148,12 +148,14 @@ public: _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; - if (b[p++] != 1) - throw std::runtime_error("unrecognized signature type"); - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature length"); - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + if (b[p++] == 1) { + if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) + throw std::runtime_error("invalid signature length"); + p += 2; + memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; + } else { + p += 2 + b.template at(p); + } p += 2 + b.template at(p); if (p > b.size()) diff --git a/node/Topology.cpp b/node/Topology.cpp index 0cd3db9e..f19d8656 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -417,6 +417,7 @@ void Topology::_memoizeUpstreams() // assumes _upstreams_m and _peers_m are locked _upstreamAddresses.clear(); _amRoot = false; + for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { if (i->identity == RR->identity) { _amRoot = true; @@ -429,6 +430,7 @@ void Topology::_memoizeUpstreams() } } } + for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { if (i->identity == RR->identity) { @@ -443,6 +445,15 @@ void Topology::_memoizeUpstreams() } } } + + std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); + + _cor.clear(); + for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { + if (!_cor.addRepresentative(*a)) + break; + } + _cor.sign(RR->identity,RR->node->now()); } } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 78dc0fe8..dca35789 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -38,6 +38,7 @@ #include "InetAddress.hpp" #include "Hashtable.hpp" #include "World.hpp" +#include "CertificateOfRepresentation.hpp" namespace ZeroTier { @@ -383,6 +384,25 @@ public: _trustedPathCount = count; } + /** + * @return Current certificate of representation (copy) + */ + inline CertificateOfRepresentation certificateOfRepresentation() const + { + Mutex::Lock _l(_upstreams_m); + return _cor; + } + + /** + * @param buf Buffer to receive COR + */ + template + void appendCertificateOfRepresentation(Buffer &buf) + { + Mutex::Lock _l(_upstreams_m); + _cor.serialize(buf); + } + private: Identity _getIdentity(const Address &zta); void _memoizeUpstreams(); @@ -404,6 +424,7 @@ private: std::vector _moons; std::vector
_contactingMoons; std::vector
_upstreamAddresses; + CertificateOfRepresentation _cor; bool _amRoot; Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; -- cgit v1.2.3 From 43182f8f57483a47f1b44cdcf9dbb5387511afc2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sun, 5 Feb 2017 16:19:03 -0800 Subject: Docs, code cleanup, and protect the extra new fields of HELLO with encryption as a precaution. --- doc/MANUAL.md | 12 +++---- node/Constants.hpp | 5 +++ node/Identity.cpp | 6 ++-- node/IncomingPacket.cpp | 88 +++++++++++++++++++++++++++++-------------------- node/Node.cpp | 4 +-- node/Packet.cpp | 62 +++++++++++++++++++++++----------- node/Packet.hpp | 31 ++++++++++++++--- node/Peer.cpp | 22 ++++++++----- node/Peer.hpp | 3 +- node/Salsa20.cpp | 4 +-- node/Salsa20.hpp | 34 +++---------------- node/Switch.cpp | 2 +- node/Utils.cpp | 4 +-- 13 files changed, 162 insertions(+), 115 deletions(-) (limited to 'node/Peer.cpp') diff --git a/doc/MANUAL.md b/doc/MANUAL.md index e84146f3..e0117a4d 100644 --- a/doc/MANUAL.md +++ b/doc/MANUAL.md @@ -72,13 +72,11 @@ This manual describes the design and operation of ZeroTier and its associated se ZeroTier is a smart Ethernet switch for planet Earth. -We've re-thought networking from first principles to deliver the flat end-to-end simplicity of the original pre-NAT pre-mobility Internet in a way that meets the security and mobility requirements of the 21st century. ZeroTier transforms the world into a unified modern data center where VPN, SDN, SD-WAN, and application peer to peer networking converge and where the distinction between the cloud and the endpoint largely disappears. All the complexity of managing these networking aspects as disparate systems is replaced by the simplicity of a single virtual cloud. +We've re-thought networking from first principles to deliver the flat end-to-end simplicity of the original pre-NAT pre-mobility Internet, yet in a way that meets the security and mobility needs of the 21st century. ZeroTier erases the distinction between cloud and endpoint, bringing modern data center SDN to every device regardless of its physical location. The objectives of VPN, SDN, SD-WAN, and application peer to peer networking can all be achieved together and with reduced complexity. -At first some users struggle with this paradigm, finding it difficult to forget the fragmentation and complexity that has accreted around networking over the past decade or two. We urge skeptical users to just try it and see how many networking acronyms vanish before their eyes. +Unlike most networking products it won't take you hours, days, or weeks to test or deploy ZeroTier. Most of the time everything just works with zero configuration, and most users with some level of TCP/IP knowledge can get up and running in minutes. More advanced features like federation, rules, micro-segmentation, capability based security credentials, network monitoring, and clustering are available but you don't need to worry about them until they're needed. -Unlike most networking products it won't take you hours, days, or weeks to test or deploy ZeroTier. Most of the time everything just works with zero configuration, and most users with some level of TCP/IP knowledge can get up and running in minutes. More advanced features like rules, micro-segmentation, capability based security credentials, network monitoring, and clustering are available but you don't need to worry about them until they're needed. - -The first section (2) of this guide explains ZeroTier's design and operation in detail and is written for users with at least an intermediate knowledge of topics like TCP/IP and Ethernet networking. Reading and understanding everything in it is not mandatory but we've written it as a deep technical dive as serious IT users typically like to understand the systems they deploy and use. Sections 3 and 4 deal more concretely with the ZeroTier One endpoint service software and how to deploy for common use cases. +The first section (2) of this guide explains ZeroTier's design and operation in detail and is written for users with at least an intermediate knowledge of topics like TCP/IP and Ethernet networking. All of it is not required reading for most users, but we've created a deep technical dive to satisfy the desire of IT professionals to understand the systems that they use. Sections 3 and 4 deal more concretely with the ZeroTier One endpoint service software and how to deploy for common use cases. ## **2.** How it Works @@ -88,7 +86,7 @@ ZeroTier is comprised of two closely coupled but conceptually distinct layers [i To build a planetary data center we first had to begin with the wiring. Tunneling into the Earth's core and putting a giant wire closet down there wasn't an option, so we decided to use software to build virtual wires over the existing Internet instead. -In conventional networks L1 (OSI layer 1) refers to the actual CAT5/CAT6 cables or wireless radio channels over which data is carried and the physical transciever chips that modulate and demodulate it. VL1 is a peer to peer network that does the same thing by using encryption, authentication, and a lot of networking tricks to create virtual wires as needed. +In conventional networks L1 (OSI layer 1) refers to the actual CAT5/CAT6 cables or wireless radio channels over which data is carried and the physical transciever chips that modulate and demodulate it. VL1 is a peer to peer network that does the same thing by using encryption, authentication, and a lot of networking tricks to create virtual wires on a dyniamic as-needed basis. ### **2.1.1.** Network Topology and Peer Discovery @@ -98,7 +96,7 @@ Roots run the same software as regular endpoints but reside at fast stable locat There is only one planet. Earth's root servers are operated by ZeroTier, Inc. as a free service. Their presence defines and unifies the global data center where we all reside. -Users can create "moons." These nominate additional roots for redundancy or performance. The most common reasons for doing this are to eliminate hard dependency on ZeroTier's third party infrastructure or to designate local roots inside your building or cloud so ZeroTier can work without a connection to the Internet. Moons are by no means required and most of our users get by just fine without them. +Moons can be created by users. These nominate additional roots for redundancy or performance. The most common reasons for doing this are to eliminate hard dependency on ZeroTier's third party infrastructure or to designate local roots inside your building or cloud so ZeroTier can work without a connection to the Internet. Moons are by no means required and most of our users get by just fine without them. When peers start out they have no direct links to one another, only upstream to roots. Every peer on VL1 possesses a globally unique address, but unlike IP addresses these are opaque cryptographic identifiers that encode no routing information. To communicate peers first send packets "up" the tree, and as these packets traverse the network they trigger the opportunistic creation of direct links along the way. The tree is constantly trying to "collapse itself" to optimize itself to the pattern of traffic it is carrying. diff --git a/node/Constants.hpp b/node/Constants.hpp index be4eb475..3bda3805 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -293,6 +293,11 @@ */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) +/** + * Send a full HELLO every this often (ms) + */ +#define ZT_PEER_SEND_FULL_HELLO_EVERY (ZT_PEER_PING_PERIOD * 2) + /** * How often to retry expired paths that we're still remembering */ diff --git a/node/Identity.cpp b/node/Identity.cpp index 05b70873..89fdb836 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -46,7 +46,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub // but is not what we want for sequential memory-harndess. memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); Salsa20 s20(digest,256,(char *)digest + 32); - s20.encrypt20((char *)genmem,(char *)genmem,64); + s20.crypt20((char *)genmem,(char *)genmem,64); for(unsigned long i=64;i(ZT_PROTO_VERB_HELLO_IDX_REVISION); const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - Identity id; - InetAddress externalSurfaceAddress; - uint64_t planetWorldId = 0; - uint64_t planetWorldTimestamp = 0; - std::vector< std::pair > moonIdsAndTimestamps; - { - unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - - // Get external surface address if present (was not in old versions) - if (ptr < size()) - ptr += externalSurfaceAddress.deserialize(*this,ptr); - - // Get primary planet world ID and world timestamp if present - if ((ptr + 16) <= size()) { - planetWorldId = at(ptr); ptr += 8; - planetWorldTimestamp = at(ptr); - } - - // Get moon IDs and timestamps if present - if ((ptr + 2) <= size()) { - unsigned int numMoons = at(ptr); ptr += 2; - for(unsigned int i=0;i(at(ptr),at(ptr + 8))); - ptr += 16; - } - } + if (protoVersion < ZT_PROTO_VERSION_MIN) { + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + return true; } + Identity id; + unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str()); - return true; - } - if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str()); return true; } @@ -324,6 +299,43 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut // VALID -- if we made it here, packet passed identity and authenticity checks! + // Get external surface address if present (was not in old versions) + InetAddress externalSurfaceAddress; + if (ptr < size()) + ptr += externalSurfaceAddress.deserialize(*this,ptr); + + // Get primary planet world ID and world timestamp if present + uint64_t planetWorldId = 0; + uint64_t planetWorldTimestamp = 0; + if ((ptr + 16) <= size()) { + planetWorldId = at(ptr); ptr += 8; + planetWorldTimestamp = at(ptr); + } + + std::vector< std::pair > moonIdsAndTimestamps; + if (ptr < size()) { + // Remainder of packet, if present, is encrypted + cryptField(peer->key(),ptr,size() - ptr); + + // Get moon IDs and timestamps if present + if ((ptr + 2) <= size()) { + unsigned int numMoons = at(ptr); ptr += 2; + for(unsigned int i=0;i(at(ptr),at(ptr + 8))); + ptr += 16; + } + } + + // Handle COR if present (older versions don't send this) + if ((ptr + 2) <= size()) { + //const unsigned int corSize = at(ptr); ptr += 2; + ptr += 2; + CertificateOfRepresentation cor; + ptr += cor.deserialize(*this,ptr); + } + } + // Learn our external surface address from other peers to help us negotiate symmetric NATs // and detect changes to our global IP that can trigger path renegotiation. if ((externalSurfaceAddress)&&(hops() == 0)) @@ -337,6 +349,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + if (protoVersion >= 5) { _path->address().serialize(outp); } else { @@ -387,6 +400,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut } outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); + const unsigned int corSizeAt = outp.size(); + outp.addSize(2); + RR->topology->appendCertificateOfRepresentation(outp); + outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); + outp.armor(peer->key(),true); _path->send(RR,outp.data(),outp.size(),now); @@ -586,7 +604,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now()); + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1155,7 +1173,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now,false); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1174,7 +1192,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(InetAddress(),a,now); + peer->attemptToContactAt(InetAddress(),a,now,false); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } diff --git a/node/Node.cpp b/node/Node.cpp index 3d5b5c3d..b8e74a52 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -70,7 +70,7 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : Utils::getSecureRandom(foo,32); _prng.init(foo,256,foo); memset(_prngStream,0,sizeof(_prngStream)); - _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); std::string idtmp(dataStoreGet("identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { @@ -686,7 +686,7 @@ uint64_t Node::prng() { unsigned int p = (++_prngStreamPtr % ZT_NODE_PRNG_BUF_SIZE); if (!p) - _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream)); + _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); return _prngStream[p]; } diff --git a/node/Packet.cpp b/node/Packet.cpp index 05fe8dd9..a1bb3132 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -18,9 +18,21 @@ #include #include +#include +#include +#include #include "Packet.hpp" +#ifdef _MSC_VER +#define FORCE_INLINE static __forceinline +#include +#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#else +#define FORCE_INLINE static inline +#endif + namespace ZeroTier { /************************************************************************** */ @@ -367,7 +379,7 @@ LZ4_decompress_*_continue() : #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -#include +//#include typedef struct { uint32_t hashTable[LZ4_HASH_SIZE_U32]; @@ -536,6 +548,7 @@ union LZ4_streamDecode_u { /*-************************************ * Compiler Options **************************************/ +#if 0 #ifdef _MSC_VER /* Visual Studio */ # define FORCE_INLINE static __forceinline # include @@ -550,6 +563,7 @@ union LZ4_streamDecode_u { # define FORCE_INLINE static # endif #endif /* _MSC_VER */ +#endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) @@ -564,38 +578,39 @@ union LZ4_streamDecode_u { /*-************************************ * Memory routines **************************************/ -#include /* malloc, calloc, free */ +//#include /* malloc, calloc, free */ #define ALLOCATOR(n,s) calloc(n,s) #define FREEMEM free -#include /* memset, memcpy */ +//#include /* memset, memcpy */ #define MEM_INIT memset /*-************************************ * Basic Types **************************************/ -#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# include +//#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +//# include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; -#else +/*#else typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; typedef unsigned long long U64; - typedef size_t uptrval; /* generally true, except OpenVMS-64 */ -#endif + typedef size_t uptrval; +#endif */ -#if defined(__x86_64__) - typedef U64 reg_t; /* 64-bits in x32 mode */ -#else - typedef size_t reg_t; /* 32-bits in x32 mode */ -#endif +typedef uintptr_t reg_t; +//#if defined(__x86_64__) +// typedef U64 reg_t; /* 64-bits in x32 mode */ +//#else +// typedef size_t reg_t; /* 32-bits in x32 mode */ +//#endif /*-************************************ * Reading and writing into memory @@ -606,7 +621,6 @@ static unsigned LZ4_isLittleEndian(void) return one.c[0]; } - #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) /* lie to the compiler about data alignment; use with caution */ @@ -1975,10 +1989,10 @@ void Packet::armor(const void *key,bool encryptPayload) // MAC key is always the first 32 bytes of the Salsa20 key stream // This is the same construction DJB's NaCl library uses - s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey)); + s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); if (encryptPayload) - s20.encrypt12(payload,payload,payloadLen); + s20.crypt12(payload,payload,payloadLen); Poly1305::compute(mac,payload,payloadLen,macKey); memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8); @@ -1995,20 +2009,30 @@ bool Packet::dearmor(const void *key) if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/); + Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); - s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey)); + s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); Poly1305::compute(mac,payload,payloadLen,macKey); if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8)) return false; if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) - s20.decrypt12(payload,payload,payloadLen); + s20.crypt12(payload,payload,payloadLen); return true; } else return false; // unrecognized cipher suite } +void Packet::cryptField(const void *key,unsigned int start,unsigned int len) +{ + unsigned char mangledKey[32]; + uint64_t iv = Utils::hton((uint64_t)start ^ at(ZT_PACKET_IDX_IV)); + _salsa20MangleKey((const unsigned char *)key,mangledKey); + Salsa20 s20(mangledKey,256,&iv); + unsigned char *const ptr = field(start,len); + s20.crypt12(ptr,ptr,len); +} + bool Packet::compress() { unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; diff --git a/node/Packet.hpp b/node/Packet.hpp index 7d404b25..03bd9ed3 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -542,6 +542,7 @@ public: * [<[...] destination address to which packet was sent>] * <[8] 64-bit world ID of current planet> * <[8] 64-bit timestamp of current planet> + * [... remainder if packet is encrypted using cryptField() ...] * <[2] 16-bit number of moons> * [<[1] 8-bit type ID of moon>] * [<[8] 64-bit world ID of moon>] @@ -550,9 +551,10 @@ public: * <[2] 16-bit length of certificate of representation> * [... certificate of representation ...] * - * HELLO is sent in the clear, and therefore cannot contain anything - * secret or highly confidential. It should contain nothing that is - * not either public or easy to obtain via other means. + * The initial fields of HELLO are sent in the clear. Fields after the + * planet definition (which are common knowledge) are however encrypted + * using the cryptField() function. The packet is MAC'd as usual using + * the same MAC construct as other packets. * * The destination address is the wire address to which this packet is * being sent, and in OK is *also* the destination address of the OK @@ -566,7 +568,7 @@ public: * 0x04 - 6-byte IPv4 UDP address/port -- format: <[4] IP>, <[2] port> * 0x06 - 18-byte IPv6 UDP address/port -- format: <[16] IP>, <[2] port> * - * OK payload: + * OK payload (note that OK is encrypted): * <[8] timestamp (echoed from original HELLO)> * <[1] protocol version (of responder)> * <[1] software major version (of responder)> @@ -576,6 +578,8 @@ public: * [<[...] destination address>] * <[2] 16-bit length of world update or 0 if none> * [[...] updates to planets and/or moons] + * <[2] 16-bit length of certificate of representation (of responder)> + * [... certificate of representation ...] * * ERROR has no payload. */ @@ -1348,6 +1352,25 @@ public: */ bool dearmor(const void *key); + /** + * Encrypt/decrypt a separately armored portion of a packet + * + * This keys using the same key in the same way as armor/dearmor, but + * uses a different IV computed from the packet's IV plus the starting + * point index. + * + * This currently uses Salsa20/12, but any message that uses this should + * incorporate a cipher selector to permit this to be changed later. + * + * This is currently only used to mask portions of HELLO as an extra + * security precation since most of that message is sent in the clear. + * + * @param key 32-byte key + * @param start Start of encrypted portion + * @param len Length of encrypted portion + */ + void cryptField(const void *key,unsigned int start,unsigned int len); + /** * Attempt to compress payload if not already (must be unencrypted) * diff --git a/node/Peer.cpp b/node/Peer.cpp index bb6b945d..338bea10 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -203,7 +203,7 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(path->localAddress(),path->address(),now); + attemptToContactAt(path->localAddress(),path->address(),now,true); path->sent(now); } } @@ -357,6 +357,8 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u outp.append((uint64_t)RR->topology->planetWorldId()); outp.append((uint64_t)RR->topology->planetWorldTimestamp()); + const unsigned int startCryptedPortionAt = outp.size(); + std::vector moons(RR->topology->moons()); outp.append((uint16_t)moons.size()); for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { @@ -368,21 +370,23 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u const unsigned int corSizeAt = outp.size(); outp.addSize(2); RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)((outp.size() - corSizeAt) - 2)); + outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); + + outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); RR->node->expectReplyTo(outp.packetId()); if (atAddress) { - outp.armor(_key,false); + outp.armor(_key,false); // false == don't encrypt full payload, but add MAC RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { - RR->sw->send(outp,false); + RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) +void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello) { - if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { + if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true); @@ -398,7 +402,7 @@ void Peer::tryMemorizedPath(uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(_id.address(),-1,mp)) - attemptToContactAt(InetAddress(),mp,now); + attemptToContactAt(InetAddress(),mp,now,true); } } @@ -420,7 +424,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now); + attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false); _paths[bestp].path->sent(now); } return true; @@ -444,7 +448,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now); + attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false); _paths[p].path->sent(now); _paths[p].lastReceive = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index e79739a3..a3ec0088 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -161,8 +161,9 @@ public: * @param localAddr Local address * @param atAddress Destination address * @param now Current time + * @param sendFullHello If true, always send a full HELLO instead of just an ECHO */ - void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello); /** * Try a memorized or statically defined path if any are known diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp index 3aa19ac6..1a4641f7 100644 --- a/node/Salsa20.cpp +++ b/node/Salsa20.cpp @@ -123,7 +123,7 @@ void Salsa20::init(const void *key,unsigned int kbits,const void *iv) #endif } -void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes) +void Salsa20::crypt12(const void *in,void *out,unsigned int bytes) throw() { uint8_t tmp[64]; @@ -623,7 +623,7 @@ void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes) } } -void Salsa20::encrypt20(const void *in,void *out,unsigned int bytes) +void Salsa20::crypt20(const void *in,void *out,unsigned int bytes) throw() { uint8_t tmp[64]; diff --git a/node/Salsa20.hpp b/node/Salsa20.hpp index 7e4c1e53..6405d450 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -56,51 +56,25 @@ public: throw(); /** - * Encrypt data using Salsa20/12 + * Encrypt/decrypt data using Salsa20/12 * * @param in Input data * @param out Output buffer * @param bytes Length of data */ - void encrypt12(const void *in,void *out,unsigned int bytes) + void crypt12(const void *in,void *out,unsigned int bytes) throw(); /** - * Encrypt data using Salsa20/20 + * Encrypt/decrypt data using Salsa20/20 * * @param in Input data * @param out Output buffer * @param bytes Length of data */ - void encrypt20(const void *in,void *out,unsigned int bytes) + void crypt20(const void *in,void *out,unsigned int bytes) throw(); - /** - * Decrypt data - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - inline void decrypt12(const void *in,void *out,unsigned int bytes) - throw() - { - encrypt12(in,out,bytes); - } - - /** - * Decrypt data - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - inline void decrypt20(const void *in,void *out,unsigned int bytes) - throw() - { - encrypt20(in,out,bytes); - } - private: union { #ifdef ZT_SALSA20_SSE diff --git a/node/Switch.cpp b/node/Switch.cpp index a769faea..346091a4 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -777,7 +777,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { #endif if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now); + peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false); viaPath->sent(now); } #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Utils.cpp b/node/Utils.cpp index 06b726cc..247dd54a 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -182,7 +182,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) #else // not __WINDOWS__ - static char randomBuf[131072]; + static char randomBuf[65536]; static unsigned int randomPtr = sizeof(randomBuf); static int devURandomFd = -1; @@ -215,7 +215,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) #endif // __WINDOWS__ or not - s20.encrypt12(buf,buf,bytes); + s20.crypt12(buf,buf,bytes); } bool Utils::scopy(char *dest,unsigned int len,const char *src) -- cgit v1.2.3 From e4b6611201bb2f69c05a4c104c77d6ec51c2c38b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 13 Feb 2017 09:46:34 -0800 Subject: Only accept world updates from upstreams. --- node/IncomingPacket.cpp | 20 ++++++++++++-------- node/Peer.cpp | 8 +++++++- node/Topology.hpp | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 9 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 8836df9f..c6cf7f36 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -449,22 +449,26 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p InetAddress externalSurfaceAddress; unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; - // Get reported external surface address if present (was not on old versions) + // Get reported external surface address if present if (ptr < size()) ptr += externalSurfaceAddress.deserialize(*this,ptr); - // Handle planet or moon updates if present (older versions don't send this) + // Handle planet or moon updates if present if ((ptr + 2) <= size()) { const unsigned int worldLen = at(ptr); ptr += 2; - const unsigned int endOfWorlds = ptr + worldLen; - while (ptr < endOfWorlds) { - World w; - ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(w); + if (RR->topology->isUpstream(peer->identity())) { + const unsigned int endOfWorlds = ptr + worldLen; + while (ptr < endOfWorlds) { + World w; + ptr += w.deserialize(*this,ptr); + RR->topology->addWorld(w); + } + } else { + ptr += worldLen; } } - // Handle COR if present (older versions don't send this) + // Handle certificate of representation if present if ((ptr + 2) <= size()) { if (at(ptr) > 0) { CertificateOfRepresentation cor; diff --git a/node/Peer.cpp b/node/Peer.cpp index 338bea10..d5847092 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -360,12 +360,18 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u const unsigned int startCryptedPortionAt = outp.size(); std::vector moons(RR->topology->moons()); - outp.append((uint16_t)moons.size()); + std::vector moonsWanted(RR->topology->moonsWanted()); + outp.append((uint16_t)(moons.size() + moonsWanted.size())); for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { outp.append((uint8_t)m->type()); outp.append((uint64_t)m->id()); outp.append((uint64_t)m->timestamp()); } + for(std::vector::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) { + outp.append((uint8_t)World::TYPE_MOON); + outp.append(*m); + outp.append((uint64_t)0); + } const unsigned int corSizeAt = outp.size(); outp.addSize(2); diff --git a/node/Topology.hpp b/node/Topology.hpp index 2465de64..35f98ccc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -215,6 +215,20 @@ public: return _moons; } + /** + * @return Moon IDs we are waiting for from seeds + */ + inline std::vector moonsWanted() const + { + Mutex::Lock _l(_upstreams_m); + std::vector mw; + for(std::vector< std::pair >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { + if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) + mw.push_back(s->first); + } + return mw; + } + /** * @return Current planet */ -- cgit v1.2.3 From afba19e01cc5db2030059485217e5fddadfa3ee1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 16 Feb 2017 09:44:04 -0800 Subject: When deciding whether to send PUSH_DIRECT_PATHS we should check global trust flag, not the one passed into receive(). --- node/Peer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index d5847092..25efab42 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -207,7 +207,7 @@ void Peer::received( path->sent(now); } } - } else if (trustEstablished) { + } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) #ifdef ZT_ENABLE_CLUSTER // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection -- cgit v1.2.3 From 2bf9145ae65385bf968542619ffcf204cf6241d8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 1 Mar 2017 10:22:57 -0800 Subject: Outgoing side of packet counter for link quality reporting. Also some cleanup and a cluster mode build fix. --- node/Buffer.hpp | 44 +- node/Cluster.cpp | 8 +- node/IncomingPacket.cpp | 26 +- node/Node.cpp | 6 +- node/Packet.cpp | 1942 +++++++++++++++++++++++------------------------ node/Packet.hpp | 25 +- node/Path.hpp | 10 + node/Peer.cpp | 24 +- node/Peer.hpp | 6 +- node/Switch.cpp | 8 +- 10 files changed, 1053 insertions(+), 1046 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 1a478894..37f39e7b 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -79,8 +79,7 @@ public: inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } - Buffer() - throw() : + Buffer() : _l(0) { } @@ -419,87 +418,70 @@ public: /** * Set buffer data length to zero */ - inline void clear() - throw() - { - _l = 0; - } + inline void clear() { _l = 0; } /** * Zero buffer up to size() */ - inline void zero() - throw() - { - memset(_b,0,_l); - } + inline void zero() { memset(_b,0,_l); } /** * Zero unused capacity area */ - inline void zeroUnused() - throw() - { - memset(_b + _l,0,C - _l); - } + inline void zeroUnused() { memset(_b + _l,0,C - _l); } /** * Unconditionally and securely zero buffer's underlying memory */ - inline void burn() - throw() - { - Utils::burn(_b,sizeof(_b)); - } + inline void burn() { Utils::burn(_b,sizeof(_b)); } /** * @return Constant pointer to data in buffer */ - inline const void *data() const throw() { return _b; } + inline const void *data() const { return _b; } + + /** + * @return Non-constant pointer to data in buffer + */ + inline void *unsafeData() { return _b; } /** * @return Size of data in buffer */ - inline unsigned int size() const throw() { return _l; } + inline unsigned int size() const { return _l; } /** * @return Capacity of buffer */ - inline unsigned int capacity() const throw() { return C; } + inline unsigned int capacity() const { return C; } template inline bool operator==(const Buffer &b) const - throw() { return ((_l == b._l)&&(!memcmp(_b,b._b,_l))); } template inline bool operator!=(const Buffer &b) const - throw() { return ((_l != b._l)||(memcmp(_b,b._b,_l))); } template inline bool operator<(const Buffer &b) const - throw() { return (memcmp(_b,b._b,std::min(_l,b._l)) < 0); } template inline bool operator>(const Buffer &b) const - throw() { return (b < *this); } template inline bool operator<=(const Buffer &b) const - throw() { return !(b < *this); } template inline bool operator>=(const Buffer &b) const - throw() { return !(*this < b); } diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 00122402..52e03ffe 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -255,7 +255,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") char polykey[ZT_POLY1305_KEY_LEN]; memset(polykey,0,sizeof(polykey)); - s20.encrypt12(polykey,polykey,sizeof(polykey)); + s20.crypt12(polykey,polykey,sizeof(polykey)); // Compute 16-byte MAC char mac[ZT_POLY1305_MAC_LEN]; @@ -267,7 +267,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) // Decrypt! dmsg.setSize(len - 24); - s20.decrypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); + s20.crypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); } if (dmsg.size() < 4) @@ -954,10 +954,10 @@ void Cluster::_flush(uint16_t memberId) // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") char polykey[ZT_POLY1305_KEY_LEN]; memset(polykey,0,sizeof(polykey)); - s20.encrypt12(polykey,polykey,sizeof(polykey)); + s20.crypt12(polykey,polykey,sizeof(polykey)); // Encrypt m.q in place - s20.encrypt12(reinterpret_cast(m.q.data()) + 24,const_cast(reinterpret_cast(m.q.data())) + 24,m.q.size() - 24); + s20.crypt12(reinterpret_cast(m.q.data()) + 24,const_cast(reinterpret_cast(m.q.data())) + 24,m.q.size() - 24); // Add MAC for authentication (encrypt-then-MAC) char mac[ZT_POLY1305_MAC_LEN]; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b5b2bcb3..85b06d50 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -243,7 +243,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true); + outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } else { TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); @@ -405,7 +405,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut RR->topology->appendCertificateOfRepresentation(outp); outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -584,7 +584,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr } if (count > 0) { - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -610,7 +610,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false); + rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false,0); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -732,7 +732,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -762,7 +762,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append((uint64_t)pid); if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); @@ -957,7 +957,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -984,7 +984,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared outp.append((uint64_t)packetId()); outp.append((uint64_t)network->id()); outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } @@ -1033,7 +1033,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar outp.append((uint32_t)mg.adi()); const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); if (gatheredLocally > 0) { - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } @@ -1140,7 +1140,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share outp.append((uint32_t)to.adi()); outp.append((unsigned char)0x02); // flag 0x02 = contains gather results if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } @@ -1198,7 +1198,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(InetAddress(),a,now,false); + peer->attemptToContactAt(InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1217,7 +1217,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(InetAddress(),a,now,false); + peer->attemptToContactAt(InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1447,7 +1447,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,cons outp.append(packetId()); outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,outp.data(),outp.size(),now); } } diff --git a/node/Node.cpp b/node/Node.cpp index 6dc89387..35940d27 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -180,7 +180,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(InetAddress(),addr,_now); + p->sendHELLO(InetAddress(),addr,_now,0); contacted = true; break; } @@ -190,7 +190,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(InetAddress(),addr,_now); + p->sendHELLO(InetAddress(),addr,_now,0); contacted = true; break; } @@ -200,7 +200,7 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(up->localAddress(),up->address(),_now); + p->sendHELLO(up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); diff --git a/node/Packet.cpp b/node/Packet.cpp index 790f4b09..82a5d7ea 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -65,9 +65,9 @@ namespace { modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -85,8 +85,8 @@ namespace { OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ /* --- Dependency --- */ @@ -101,9 +101,9 @@ namespace { The LZ4 compression library provides in-memory compression and decompression functions. Compression can be done in: - - a single step (described as Simple Functions) - - a single step, reusing a context (described in Advanced Functions) - - unbounded multiple steps (described as Streaming compression) + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) lz4.h provides block compression functions. It gives full buffer control to user. Decompressing an lz4-compressed block also requires metadata (such as compressed size). @@ -164,28 +164,28 @@ namespace { * Simple Functions **************************************/ /*! LZ4_compress_default() : - Compresses 'sourceSize' bytes from buffer 'source' - into already allocated 'dest' buffer of size 'maxDestSize'. - Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). - It also runs faster, so it's a recommended setting. - If the function cannot compress 'source' into a more limited 'dest' budget, - compression stops *immediately*, and the function result is zero. - As a consequence, 'dest' content is not valid. - This function never writes outside 'dest' buffer, nor read outside 'source' buffer. - sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE - maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) - return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) - or 0 if compression fails */ + Compresses 'sourceSize' bytes from buffer 'source' + into already allocated 'dest' buffer of size 'maxDestSize'. + Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'source' into a more limited 'dest' budget, + compression stops *immediately*, and the function result is zero. + As a consequence, 'dest' content is not valid. + This function never writes outside 'dest' buffer, nor read outside 'source' buffer. + sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) + return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) + or 0 if compression fails */ //LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); /*! LZ4_decompress_safe() : - compressedSize : is the precise full size of the compressed block. - maxDecompressedSize : is the size of destination buffer, which must be already allocated. - return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) - If destination buffer is not large enough, decoding will stop and output an error code (<0). - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function is protected against buffer overflow exploits, including malicious data packets. - It never writes outside output buffer, nor reads outside input buffer. + compressedSize : is the precise full size of the compressed block. + maxDecompressedSize : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) + If destination buffer is not large enough, decoding will stop and output an error code (<0). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against buffer overflow exploits, including malicious data packets. + It never writes outside output buffer, nor reads outside input buffer. */ LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); @@ -198,33 +198,33 @@ LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compress /*! LZ4_compressBound() : - Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) - This function is primarily useful for memory allocation purposes (destination buffer size). - Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). - Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) - inputSize : max supported value is LZ4_MAX_INPUT_SIZE - return : maximum output size in a "worst case" scenario - or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) */ LZ4LIB_API int LZ4_compressBound(int inputSize); /*! LZ4_compress_fast() : - Same as LZ4_compress_default(), but allows to select an "acceleration" factor. - The larger the acceleration value, the faster the algorithm, but also the lesser the compression. - It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. - An acceleration value of "1" is the same as regular LZ4_compress_default() - Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. + Same as LZ4_compress_default(), but allows to select an "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. */ LZ4LIB_API int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); /*! LZ4_compress_fast_extState() : - Same compression function, just using an externally allocated memory space to store compression state. - Use LZ4_sizeofState() to know how much memory must be allocated, - and allocate it on 8-bytes boundaries (using malloc() typically). - Then, provide it as 'void* state' to compression function. + Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. */ //LZ4LIB_API int LZ4_sizeofState(void); LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); @@ -232,42 +232,42 @@ LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char /*! LZ4_compress_destSize() : - Reverse the logic, by compressing as much data as possible from 'source' buffer - into already allocated buffer 'dest' of size 'targetDestSize'. - This function either compresses the entire 'source' content into 'dest' if it's large enough, - or fill 'dest' buffer completely with as much data as possible from 'source'. - *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. - New value is necessarily <= old value. - return : Nb bytes written into 'dest' (necessarily <= targetDestSize) - or 0 if compression fails + Reverse the logic, by compressing as much data as possible from 'source' buffer + into already allocated buffer 'dest' of size 'targetDestSize'. + This function either compresses the entire 'source' content into 'dest' if it's large enough, + or fill 'dest' buffer completely with as much data as possible from 'source'. + *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. + New value is necessarily <= old value. + return : Nb bytes written into 'dest' (necessarily <= targetDestSize) + or 0 if compression fails */ //LZ4LIB_API int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); /*! LZ4_decompress_fast() : - originalSize : is the original and therefore uncompressed size - return : the number of bytes read from the source buffer (in other words, the compressed size) - If the source stream is detected malformed, the function will stop decoding and return a negative result. - Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. - note : This function fully respect memory boundaries for properly formed compressed data. - It is a bit faster than LZ4_decompress_safe(). - However, it does not provide any protection against intentionally modified data stream (malicious input). - Use this function in trusted environment only (data to decode comes from a trusted source). + originalSize : is the original and therefore uncompressed size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is detected malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function fully respect memory boundaries for properly formed compressed data. + It is a bit faster than LZ4_decompress_safe(). + However, it does not provide any protection against intentionally modified data stream (malicious input). + Use this function in trusted environment only (data to decode comes from a trusted source). */ //LZ4LIB_API int LZ4_decompress_fast (const char* source, char* dest, int originalSize); /*! LZ4_decompress_safe_partial() : - This function decompress a compressed block of size 'compressedSize' at position 'source' - into destination buffer 'dest' of size 'maxDecompressedSize'. - The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, - reducing decompression time. - return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) - Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. - Always control how many bytes were decoded. - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets + This function decompress a compressed block of size 'compressedSize' at position 'source' + into destination buffer 'dest' of size 'maxDecompressedSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets */ //LZ4LIB_API int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); @@ -336,20 +336,20 @@ typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defin /*! LZ4_decompress_*_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) - In the case of a ring buffers, decoding buffer must be either : - - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) - In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). - - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. - maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including small ones ( < 64 KB). - - _At least_ 64 KB + 8 bytes + maxBlockSize. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including larger than decoding buffer. - Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, - and indicate where it is saved using LZ4_setStreamDecode() + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) + In the case of a ring buffers, decoding buffer must be either : + - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including small ones ( < 64 KB). + - _At least_ 64 KB + 8 bytes + maxBlockSize. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including larger than decoding buffer. + Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + and indicate where it is saved using LZ4_setStreamDecode() */ //LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); //LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); @@ -382,37 +382,37 @@ LZ4_decompress_*_continue() : //#include typedef struct { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t* dictionary; - uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ - uint32_t dictSize; + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; } LZ4_stream_t_internal; typedef struct { - const uint8_t* externalDict; - size_t extDictSize; - const uint8_t* prefixEnd; - size_t prefixSize; + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; #else typedef struct { - unsigned int hashTable[LZ4_HASH_SIZE_U32]; - unsigned int currentOffset; - unsigned int initCheck; - const unsigned char* dictionary; - unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */ - unsigned int dictSize; + unsigned int hashTable[LZ4_HASH_SIZE_U32]; + unsigned int currentOffset; + unsigned int initCheck; + const unsigned char* dictionary; + unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */ + unsigned int dictSize; } LZ4_stream_t_internal; typedef struct { - const unsigned char* externalDict; - size_t extDictSize; - const unsigned char* prefixEnd; - size_t prefixSize; + const unsigned char* externalDict; + size_t extDictSize; + const unsigned char* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; #endif @@ -428,8 +428,8 @@ typedef struct { #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) #define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_stream_t */ @@ -444,8 +444,8 @@ union LZ4_stream_u { #define LZ4_STREAMDECODESIZE_U64 4 #define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; - LZ4_streamDecode_t_internal internal_donotuse; + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_streamDecode_t */ /* lz4.c ------------------------------------------------------------------ */ @@ -460,9 +460,9 @@ union LZ4_streamDecode_u { modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -480,8 +480,8 @@ union LZ4_streamDecode_u { OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ @@ -617,8 +617,8 @@ typedef uintptr_t reg_t; **************************************/ static unsigned LZ4_isLittleEndian(void) { - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; } #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) @@ -648,27 +648,27 @@ static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = val static U16 LZ4_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; } static U32 LZ4_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; } static reg_t LZ4_read_ARCH(const void* memPtr) { - reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; } static void LZ4_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } static void LZ4_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ @@ -676,38 +676,38 @@ static void LZ4_write32(void* memPtr, U32 value) static U16 LZ4_readLE16(const void* memPtr) { - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); - } + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } } static void LZ4_writeLE16(void* memPtr, U16 value) { - if (LZ4_isLittleEndian()) { - LZ4_write16(memPtr, value); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); - } + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } } static void LZ4_copy8(void* dst, const void* src) { - memcpy(dst,src,8); + memcpy(dst,src,8); } /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; - do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3); + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (int)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); + return (__builtin_ctzll((U64)val) >> 3); # else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; # endif - } else /* 32 bits */ { + } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); + unsigned long r; + _BitScanForward( &r, (U32)val ); + return (int)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); + return (__builtin_ctz((U32)val) >> 3); # else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; # endif - } - } else /* Big Endian CPU */ { - if (sizeof(val)==8) { + } + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { # if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); + return (__builtin_clzll((U64)val) >> 3); # else - unsigned r; - if (!(val>>32)) { r=4; } else { r=0; val>>=32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; + unsigned r; + if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; # endif - } else /* 32 bits */ { + } else /* 32 bits */ { # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); # elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); + return (__builtin_clz((U32)val) >> 3); # else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; # endif - } - } + } + } } #define STEPSIZE sizeof(reg_t) static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { - const BYTE* const pStart = pIn; - - while (likely(pIn> ((MINMATCH*8)-(LZ4_HASHLOG+1))); - else - return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); + if (tableType == byU16) + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - if (LZ4_isLittleEndian()) - return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - else - return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); - return LZ4_hash4(LZ4_read32(p), tableType); + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); } static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { - switch (tableType) - { - case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } - case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } - case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } - } + switch (tableType) + { + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } + } } FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } - if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } - { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ + if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } + if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } + { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ } FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } /** LZ4_compress_generic() : - inlined, to ensure branches are decided at compilation time */ + inlined, to ensure branches are decided at compilation time */ FORCE_INLINE int LZ4_compress_generic( - LZ4_stream_t_internal* const cctx, - const char* const source, - char* const dest, - const int inputSize, - const int maxOutputSize, - const limitedOutput_directive outputLimited, - const tableType_t tableType, - const dict_directive dict, - const dictIssue_directive dictIssue, - const U32 acceleration) + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) { - const BYTE* ip = (const BYTE*) source; - const BYTE* base; - const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - cctx->dictSize; - const BYTE* const dictionary = cctx->dictionary; - const BYTE* const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; - const BYTE* anchor = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dest; - BYTE* const olimit = op + maxOutputSize; - - U32 forwardH; - - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ - switch(dict) - { - case noDict: - default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; - break; - case withPrefix64k: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source - cctx->dictSize; - break; - case usingExtDict: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source; - break; - } - if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (inputSizehashTable, tableType, base); - ip++; forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for ( ; ; ) { - ptrdiff_t refDelta = 0; - const BYTE* match; - BYTE* token; - - /* Find a match */ - { const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - do { - U32 const h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) goto _last_literals; - - match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); - - } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); - } - - /* Catch up */ - while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } - - /* Encode Literals */ - { unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) - return 0; - if (litLength >= RUN_MASK) { - int len = (int)litLength-RUN_MASK; - *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(litLength<dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; + + U32 forwardH; + + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ + switch(dict) + { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (inputSizehashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + ptrdiff_t refDelta = 0; + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + + } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) + || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } + + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { + int len = (int)litLength-RUN_MASK; + *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchCode; - if (ip==limit) { - unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchCode += more; - ip += more; - } - } else { - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchCode; - } - - if ( outputLimited && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) - return 0; - if (matchCode >= ML_MASK) { - *token += ML_MASK; - matchCode -= ML_MASK; - LZ4_write32(op, 0xFFFFFFFF); - while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; - op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); - } else - *token += (BYTE)(matchCode); - } - - anchor = ip; - - /* Test end of chunk */ - if (ip > mflimit) break; - - /* Fill table */ - LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } } - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) - && (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + + /* Encode MatchLength */ + { unsigned matchCode; + + if ((dict==usingExtDict) && (lowLimit==dictionary)) { + const BYTE* limit; + match += refDelta; + limit = ip + (dictEnd-match); + if (limit > matchlimit) limit = matchlimit; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + } + + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) + return 0; + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); + } + + anchor = ip; + + /* Test end of chunk */ + if (ip > mflimit) break; + + /* Fill table */ + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) + && (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: - /* Encode Last Literals */ - { size_t const lastRun = (size_t)(iend - anchor); - if ( (outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) - return 0; - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRun< (U32)maxOutputSize) ) + return 0; + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRun<internal_donotuse; - LZ4_resetStream((LZ4_stream_t*)state); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } else { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + LZ4_resetStream((LZ4_stream_t*)state); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } else { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } } int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { #if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctx; - void* const ctxPtr = &ctx; + LZ4_stream_t ctx; + void* const ctxPtr = &ctx; #endif - int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) - FREEMEM(ctxPtr); + FREEMEM(ctxPtr); #endif - return result; + return result; } #if 0 int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) { - return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); + return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); } /* hidden debug function */ /* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t ctx; - LZ4_resetStream(&ctx); + LZ4_stream_t ctx; + LZ4_resetStream(&ctx); - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); } #endif @@ -1173,189 +1173,189 @@ int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int m #if 0 static int LZ4_compress_destSize_generic( - LZ4_stream_t_internal* const ctx, - const char* const src, - char* const dst, - int* const srcSizePtr, - const int targetDstSize, - const tableType_t tableType) + LZ4_stream_t_internal* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + const int targetDstSize, + const tableType_t tableType) { - const BYTE* ip = (const BYTE*) src; - const BYTE* base = (const BYTE*) src; - const BYTE* lowLimit = (const BYTE*) src; - const BYTE* anchor = ip; - const BYTE* const iend = ip + *srcSizePtr; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dst; - BYTE* const oend = op + targetDstSize; - BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; - BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); - BYTE* const oMaxSeq = oMaxLit - 1 /* token */; - - U32 forwardH; - - - /* Init conditions */ - if (targetDstSize < 1) return 0; /* Impossible to store anything */ - if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ - if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (*srcSizePtrhashTable, tableType, base); - ip++; forwardH = LZ4_hashPosition(ip, tableType); - - /* Main Loop */ - for ( ; ; ) { - const BYTE* match; - BYTE* token; - - /* Find a match */ - { const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = 1 << LZ4_skipTrigger; - - do { - U32 h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) goto _last_literals; - - match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); - - } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match) != LZ4_read32(ip)) ); - } - - /* Catch up */ - while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } - - /* Encode Literal length */ - { unsigned litLength = (unsigned)(ip - anchor); - token = op++; - if (op + ((litLength+240)/255) + litLength > oMaxLit) { - /* Not enough space for a last match */ - op--; - goto _last_literals; - } - if (litLength>=RUN_MASK) { - unsigned len = litLength - RUN_MASK; - *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(litLength< (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (*srcSizePtrhashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = 1 << LZ4_skipTrigger; + + do { + U32 h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); + + } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literal length */ + { unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if (op + ((litLength+240)/255) + litLength > oMaxLit) { + /* Not enough space for a last match */ + op--; + goto _last_literals; + } + if (litLength>=RUN_MASK) { + unsigned len = litLength - RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< oMaxMatch) { - /* Match description too long : reduce it */ - matchLength = (15-1) + (oMaxMatch-op) * 255; - } - ip += MINMATCH + matchLength; - - if (matchLength>=ML_MASK) { - *token += ML_MASK; - matchLength -= ML_MASK; - while (matchLength >= 255) { matchLength-=255; *op++ = 255; } - *op++ = (BYTE)matchLength; - } - else *token += (BYTE)(matchLength); - } - - anchor = ip; - - /* Test end of block */ - if (ip > mflimit) break; - if (op > oMaxSeq) break; - - /* Fill table */ - LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); - LZ4_putPosition(ip, ctx->hashTable, tableType, base); - if ( (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + + /* Encode MatchLength */ + { size_t matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + + if (op + ((matchLength+240)/255) > oMaxMatch) { + /* Match description too long : reduce it */ + matchLength = (15-1) + (oMaxMatch-op) * 255; + } + ip += MINMATCH + matchLength; + + if (matchLength>=ML_MASK) { + *token += ML_MASK; + matchLength -= ML_MASK; + while (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of block */ + if (ip > mflimit) break; + if (op > oMaxSeq) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: - /* Encode Last Literals */ - { size_t lastRunSize = (size_t)(iend - anchor); - if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { - /* adapt lastRunSize to fill 'dst' */ - lastRunSize = (oend-op) - 1; - lastRunSize -= (lastRunSize+240)/255; - } - ip = anchor + lastRunSize; - - if (lastRunSize >= RUN_MASK) { - size_t accumulator = lastRunSize - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRunSize< oend) { + /* adapt lastRunSize to fill 'dst' */ + lastRunSize = (oend-op) - 1; + lastRunSize -= (lastRunSize+240)/255; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ - return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); - } else { - if (*srcSizePtr < LZ4_64Klimit) - return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); - else - return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr); - } + LZ4_resetStream(state); + + if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); + } else { + if (*srcSizePtr < LZ4_64Klimit) + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); + else + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr); + } } int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (HEAPMODE) - LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctxBody; - LZ4_stream_t* ctx = &ctxBody; + LZ4_stream_t ctxBody; + LZ4_stream_t* ctx = &ctxBody; #endif - int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); #if (HEAPMODE) - FREEMEM(ctx); + FREEMEM(ctx); #endif - return result; + return result; } #endif @@ -1366,23 +1366,23 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe #if 0 LZ4_stream_t* LZ4_createStream(void) { - LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ - LZ4_resetStream(lz4s); - return lz4s; + LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); + LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + LZ4_resetStream(lz4s); + return lz4s; } #endif void LZ4_resetStream (LZ4_stream_t* LZ4_stream) { - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); } #if 0 int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { - FREEMEM(LZ4_stream); - return (0); + FREEMEM(LZ4_stream); + return (0); } #endif @@ -1390,117 +1390,117 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream) #define HASH_UNIT sizeof(reg_t) int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { - LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; - const BYTE* p = (const BYTE*)dictionary; - const BYTE* const dictEnd = p + dictSize; - const BYTE* base; - - if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ - LZ4_resetStream(LZ4_dict); - - if (dictSize < (int)HASH_UNIT) { - dict->dictionary = NULL; - dict->dictSize = 0; - return 0; - } - - if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; - dict->currentOffset += 64 KB; - base = p - dict->currentOffset; - dict->dictionary = p; - dict->dictSize = (U32)(dictEnd - p); - dict->currentOffset += dict->dictSize; - - while (p <= dictEnd-HASH_UNIT) { - LZ4_putPosition(p, dict->hashTable, byU32, base); - p+=3; - } - - return dict->dictSize; + LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; + const BYTE* p = (const BYTE*)dictionary; + const BYTE* const dictEnd = p + dictSize; + const BYTE* base; + + if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ + LZ4_resetStream(LZ4_dict); + + if (dictSize < (int)HASH_UNIT) { + dict->dictionary = NULL; + dict->dictSize = 0; + return 0; + } + + if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; + dict->currentOffset += 64 KB; + base = p - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += dict->dictSize; + + while (p <= dictEnd-HASH_UNIT) { + LZ4_putPosition(p, dict->hashTable, byU32, base); + p+=3; + } + + return dict->dictSize; } static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) { - if ((LZ4_dict->currentOffset > 0x80000000) || - ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ - /* rescale hash table */ - U32 const delta = LZ4_dict->currentOffset - 64 KB; - const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; - int i; - for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; - else LZ4_dict->hashTable[i] -= delta; - } - LZ4_dict->currentOffset = 64 KB; - if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; - LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; - } + if ((LZ4_dict->currentOffset > 0x80000000) || + ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ + /* rescale hash table */ + U32 const delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } } int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - - const BYTE* smallest = (const BYTE*) source; - if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ - if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; - LZ4_renormDictT(streamPtr, smallest); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - - /* Check overlapping input/dictionary space */ - { const BYTE* sourceEnd = (const BYTE*) source + inputSize; - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { - streamPtr->dictSize = (U32)(dictEnd - sourceEnd); - if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; - if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; - streamPtr->dictionary = dictEnd - streamPtr->dictSize; - } - } - - /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE*)source) { - int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); - else - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); - streamPtr->dictSize += (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; - } - - /* external dictionary mode */ - { int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); - else - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); - streamPtr->dictionary = (const BYTE*)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; - } + LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + const BYTE* smallest = (const BYTE*) source; + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; + LZ4_renormDictT(streamPtr, smallest); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + /* Check overlapping input/dictionary space */ + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; + } + } + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) { + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); + else + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); + streamPtr->dictSize += (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } + + /* external dictionary mode */ + { int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); + else + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } } /* Hidden debug function, to force external dictionary mode */ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) { - LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; - int result; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; + int result; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - const BYTE* smallest = dictEnd; - if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; - LZ4_renormDictT(streamPtr, smallest); + const BYTE* smallest = dictEnd; + if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; + LZ4_renormDictT(streamPtr, smallest); - result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); - streamPtr->dictionary = (const BYTE*)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; - return result; + return result; } /*! LZ4_saveDict() : @@ -1512,18 +1512,18 @@ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* */ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { - LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; - if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ - if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; - memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); - dict->dictionary = (const BYTE*)safeBuffer; - dict->dictSize = (U32)dictSize; + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; - return dictSize; + return dictSize; } #endif @@ -1538,181 +1538,181 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) * in order to remove useless branches during compilation optimization. */ FORCE_INLINE int LZ4_decompress_generic( - const char* const source, - char* const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest when no prefix */ - const BYTE* const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ - ) + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ + ) { - /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; - - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; - const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; - - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - - - /* Special cases */ - if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); - - /* Main Loop : decode sequences */ - while (1) { - size_t length; - const BYTE* match; - size_t offset; - - /* get literal length */ - unsigned const token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) - { - if (partialDecoding) { - if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } else { - if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; op = cpy; - - /* get offset */ - offset = LZ4_readLE16(ip); ip+=2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ - LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ - - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - s = *ip++; - if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; - length += s; - } while (s==255); - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ - } - length += MINMATCH; - - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) { - if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ - - if (length <= (size_t)(lowPrefix-match)) { - /* match can be copied as a single segment from external dictionary */ - memmove(op, dictEnd - (lowPrefix-match), length); - op += length; - } else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix-match); - size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ - BYTE* const endOfMatch = op + restSize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) *op++ = *copyFrom++; - } else { - memcpy(op, lowPrefix, restSize); - op += restSize; - } } - continue; - } - - /* copy match within block */ - cpy = op + length; - if (unlikely(offset<8)) { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - memcpy(op+4, match, 4); - match -= dec64; - } else { LZ4_copy8(op, match); match+=8; } - op += 8; - - if (unlikely(cpy>oend-12)) { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); - if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op16) LZ4_wildCopy(op+8, match+8, cpy); - } - op=cpy; /* correction */ - } - - /* end of decoding */ - if (endOnInput) - return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ - else - return (int) (((const char*)ip)-source); /* Nb of input bytes read */ - - /* Overflow error detected */ + /* Local Variables */ + const BYTE* ip = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; + + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; + const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; + + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + + /* Special cases */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; + + /* get literal length */ + unsigned const token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while ( likely(endOnInput ? ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) + { + if (partialDecoding) { + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ + } else { + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; op = cpy; + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + length += s; + } while (s==255); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + + if (length <= (size_t)(lowPrefix-match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + + /* copy match within block */ + cpy = op + length; + if (unlikely(offset<8)) { + const int dec64 = dec64table[offset]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[offset]; + memcpy(op+4, match, 4); + match -= dec64; + } else { LZ4_copy8(op, match); match+=8; } + op += 8; + + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op16) LZ4_wildCopy(op+8, match+8, cpy); + } + op=cpy; /* correction */ + } + + /* end of decoding */ + if (endOnInput) + return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ + else + return (int) (((const char*)ip)-source); /* Nb of input bytes read */ + + /* Overflow error detected */ _output_error: - return (int) (-(((const char*)ip)-source))-1; + return (int) (-(((const char*)ip)-source))-1; } int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); } #if 0 int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); } int LZ4_decompress_fast(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); } #endif @@ -1726,14 +1726,14 @@ int LZ4_decompress_fast(const char* source, char* dest, int originalSize) */ LZ4_streamDecode_t* LZ4_createStreamDecode(void) { - LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t)); - return lz4s; + LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t)); + return lz4s; } int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) { - FREEMEM(LZ4_stream); - return 0; + FREEMEM(LZ4_stream); + return 0; } /*! @@ -1745,107 +1745,107 @@ int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) */ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - lz4sd->prefixSize = (size_t) dictSize; - lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; - lz4sd->externalDict = NULL; - lz4sd->extDictSize = 0; - return 1; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + lz4sd->prefixSize = (size_t) dictSize; + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->externalDict = NULL; + lz4sd->extDictSize = 0; + return 1; } /* *_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks must still be available at the memory position where they were decoded. - If it's not possible, save the relevant part of decoded data into a safe buffer, - and indicate where it stands using LZ4_setStreamDecode() + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setStreamDecode() */ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - int result; - - if (lz4sd->prefixEnd == (BYTE*)dest) { - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize += result; - lz4sd->prefixEnd += result; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize = result; - lz4sd->prefixEnd = (BYTE*)dest + result; - } - - return result; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += result; + lz4sd->prefixEnd += result; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } + + return result; } int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) { - LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; - int result; - - if (lz4sd->prefixEnd == (BYTE*)dest) { - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize += originalSize; - lz4sd->prefixEnd += originalSize; - } else { - lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); - if (result <= 0) return result; - lz4sd->prefixSize = originalSize; - lz4sd->prefixEnd = (BYTE*)dest + originalSize; - } - - return result; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } + + return result; } /* Advanced decoding functions : *_usingDict() : - These decoding functions work the same as "_continue" ones, - the dictionary must be explicitly provided within parameters + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters */ FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) { - if (dictSize==0) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); - if (dictStart+dictSize == dest) { - if (dictSize >= (int)(64 KB - 1)) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); - } - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + if (dictStart+dictSize == dest) { + if (dictSize >= (int)(64 KB - 1)) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + } + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); } int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); } /* debug function */ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } #endif @@ -1878,41 +1878,41 @@ int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base) { - MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); - lz4ds->internal_donotuse.bufferStart = base; + MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); + lz4ds->internal_donotuse.bufferStart = base; } int LZ4_resetStreamState(void* state, char* inputBuffer) { - if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ - LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); - return 0; + if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ + LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); + return 0; } void* LZ4_create (char* inputBuffer) { - LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); - LZ4_init (lz4ds, (BYTE*)inputBuffer); - return lz4ds; + LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); + LZ4_init (lz4ds, (BYTE*)inputBuffer); + return lz4ds; } char* LZ4_slideInputBuffer (void* LZ4_Data) { - LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse; - int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); - return (char*)(ctx->bufferStart + dictSize); + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse; + int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); + return (char*)(ctx->bufferStart + dictSize); } /* Obsolete streaming decompression functions */ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); } int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); } #endif @@ -1928,7 +1928,6 @@ const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #ifdef ZT_TRACE const char *Packet::verbString(Verb v) - throw() { switch(v) { case VERB_NOP: return "NOP"; @@ -1955,7 +1954,6 @@ const char *Packet::verbString(Verb v) } const char *Packet::errorString(ErrorCode e) - throw() { switch(e) { case ERROR_NONE: return "NONE"; @@ -1973,54 +1971,56 @@ const char *Packet::errorString(ErrorCode e) #endif // ZT_TRACE -void Packet::armor(const void *key,bool encryptPayload) +void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) { - unsigned char mangledKey[32]; - unsigned char macKey[32]; - unsigned char mac[16]; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen); + uint8_t mangledKey[32],macKey[32],mac[16]; + uint8_t *const data = reinterpret_cast(unsafeData()); + + // Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use + data[7] = (data[7] & 0xf8) | ((uint8_t)counter & 0x07); // Set flag now, since it affects key mangle function setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/); + Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV); // MAC key is always the first 32 bytes of the Salsa20 key stream // This is the same construction DJB's NaCl library uses s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); + uint8_t *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; if (encryptPayload) s20.crypt12(payload,payload,payloadLen); - Poly1305::compute(mac,payload,payloadLen,macKey); - memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8); + memcpy(data + ZT_PACKET_IDX_MAC,mac,8); } bool Packet::dearmor(const void *key) { - unsigned char mangledKey[32]; - unsigned char macKey[32]; - unsigned char mac[16]; + uint8_t mangledKey[32],macKey[32],mac[16]; + uint8_t *const data = reinterpret_cast(unsafeData()); const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen); - unsigned int cs = cipher(); + unsigned char *const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int cs = cipher(); if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { _salsa20MangleKey((const unsigned char *)key,mangledKey); - Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); + Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV); s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); Poly1305::compute(mac,payload,payloadLen,macKey); - if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8)) - return false; + if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) + return false; // MAC failed, packet is corrupt, modified, or is not from the sender if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) s20.crypt12(payload,payload,payloadLen); return true; - } else return false; // unrecognized cipher suite + } else { + return false; // unrecognized cipher suite + } } void Packet::cryptField(const void *key,unsigned int start,unsigned int len) @@ -2028,13 +2028,13 @@ void Packet::cryptField(const void *key,unsigned int start,unsigned int len) unsigned char mangledKey[32]; unsigned char macKey[32]; _salsa20MangleKey((const unsigned char *)key,mangledKey); - mangledKey[0] ^= 0x7f; - mangledKey[1] ^= ((start >> 8) & 0xff); - mangledKey[2] ^= (start & 0xff); // slightly alter key for this use case as an added guard against key stream reuse + mangledKey[0] ^= 0x7f; + mangledKey[1] ^= ((start >> 8) & 0xff); + mangledKey[2] ^= (start & 0xff); // slightly alter key for this use case as an added guard against key stream reuse Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)); s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); // discard the first 32 bytes of key stream (the ones use for MAC in armor()) as a precaution - unsigned char *const ptr = field(start,len); - s20.crypt12(ptr,ptr,len); + unsigned char *const ptr = field(start,len); + s20.crypt12(ptr,ptr,len); } bool Packet::compress() diff --git a/node/Packet.hpp b/node/Packet.hpp index 6482356a..2017ce8e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -351,7 +351,7 @@ namespace ZeroTier { * ZeroTier packet * * Packet format: - * <[8] 64-bit random packet ID and crypto initialization vector> + * <[8] 64-bit packet ID / crypto IV / packet counter> * <[5] destination ZT address> * <[5] source ZT address> * <[1] flags/cipher/hops> @@ -362,6 +362,14 @@ namespace ZeroTier { * * Packets smaller than 28 bytes are invalid and silently discarded. * + * The 64-bit packet ID is a strongly random value used as a crypto IV. + * Its least significant 3 bits are also used as a monotonically increasing + * (and looping) counter for sending packets to a particular recipient. This + * can be used for link quality monitoring and reporting and has no crypto + * impact as it does not increase the likelihood of an IV collision. (The + * crypto we use is not sensitive to the nature of the IV, only that it does + * not repeat.) + * * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher * selection allowing up to 7 cipher suites, F is outside-envelope flags, * and H is hop count. @@ -1102,10 +1110,8 @@ public: }; #ifdef ZT_TRACE - static const char *verbString(Verb v) - throw(); - static const char *errorString(ErrorCode e) - throw(); + static const char *verbString(Verb v); + static const char *errorString(ErrorCode e); #endif template @@ -1303,6 +1309,12 @@ public: /** * Get this packet's unique ID (the IV field interpreted as uint64_t) * + * Note that the least significant 3 bits of this ID will change when armor() + * is called to armor the packet for transport. This is because armor() will + * mask the last 3 bits against the send counter for QoS monitoring use prior + * to actually using the IV to encrypt and MAC the packet. Be aware of this + * when grabbing the packetId of a new packet prior to armor/send. + * * @return Packet ID */ inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } @@ -1337,8 +1349,9 @@ public: * * @param key 32-byte key * @param encryptPayload If true, encrypt packet payload, else just MAC + * @param counter Packet send counter for destination peer -- only least significant 3 bits are used */ - void armor(const void *key,bool encryptPayload); + void armor(const void *key,bool encryptPayload,unsigned int counter); /** * Verify and (if encrypted) decrypt packet diff --git a/node/Path.hpp b/node/Path.hpp index 5993be69..626f2f4f 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -105,6 +105,7 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), + _outgoingPacketCounter(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -115,6 +116,7 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), + _outgoingPacketCounter(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -241,10 +243,18 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } + /** + * Return and increment outgoing packet counter (used with Packet::armor()) + * + * @return Next value that should be used for outgoing packet counter (only least significant 3 bits are used) + */ + inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } + private: uint64_t _lastOut; uint64_t _lastIn; uint64_t _lastTrustEstablishedPacketReceived; + unsigned int _outgoingPacketCounter; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index 25efab42..c4c8774e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -101,7 +101,7 @@ void Peer::received( outp.append(redirectTo.rawIpData(),16); } outp.append((uint16_t)redirectTo.port()); - outp.armor(_key,true); + outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } else { // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. @@ -116,7 +116,7 @@ void Peer::received( outp.append((uint8_t)16); outp.append(redirectTo.rawIpData(),16); } - outp.armor(_key,true); + outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } suboptimalPath = true; @@ -203,7 +203,7 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(path->localAddress(),path->address(),now,true); + attemptToContactAt(path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } } @@ -277,7 +277,7 @@ void Peer::received( if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true); + outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } } @@ -342,7 +342,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) } } -void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) +void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -383,22 +383,22 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u RR->node->expectReplyTo(outp.packetId()); if (atAddress) { - outp.armor(_key,false); // false == don't encrypt full payload, but add MAC + outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello) +void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,true); + outp.armor(_key,true,counter); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } else { - sendHELLO(localAddr,atAddress,now); + sendHELLO(localAddr,atAddress,now,counter); } } @@ -408,7 +408,7 @@ void Peer::tryMemorizedPath(uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(_id.address(),-1,mp)) - attemptToContactAt(InetAddress(),mp,now,true); + attemptToContactAt(InetAddress(),mp,now,true,0); } } @@ -430,7 +430,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false); + attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); _paths[bestp].path->sent(now); } return true; @@ -454,7 +454,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false); + attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); _paths[p].path->sent(now); _paths[p].lastReceive = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index a3ec0088..783f48b8 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -150,8 +150,9 @@ public: * @param localAddr Local address * @param atAddress Destination address * @param now Current time + * @param counter Outgoing packet counter */ - void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now); + void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -162,8 +163,9 @@ public: * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO + * @param counter Outgoing packet counter */ - void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello); + void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known diff --git a/node/Switch.cpp b/node/Switch.cpp index 346091a4..bf309e36 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -88,7 +88,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses _lastBeaconResponse = now; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),true); + outp.armor(peer->key(),true,path->nextOutgoingCounter()); path->send(RR,outp.data(),outp.size(),now); } } @@ -777,7 +777,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { #endif if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false); + peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } #ifdef ZT_ENABLE_CLUSTER @@ -825,14 +825,14 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if (trustedPathId) { packet.setTrusted(trustedPathId); } else { - packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt); + packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt,(viaPath) ? viaPath->nextOutgoingCounter() : 0); } #else const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); if (trustedPathId) { packet.setTrusted(trustedPathId); } else { - packet.armor(peer->key(),encrypt); + packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); } #endif -- cgit v1.2.3 From 1d39be61b267a85adebeee9e979bd1d84f55da3c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 1 Mar 2017 14:36:52 -0800 Subject: ZeroTier now has link quality measurement. We are not using this yet but decided to put it in to prep for future QoS support and SD-WAN stuff. --- include/ZeroTierOne.h | 10 ++++++++ node/Node.cpp | 3 ++- node/Packet.hpp | 13 ++++++++--- node/Path.hpp | 60 ++++++++++++++++++++++++++++++++++++++++++++---- node/Peer.cpp | 3 +++ node/Switch.cpp | 24 +++++++++---------- node/Utils.hpp | 14 +++++++++++ one.cpp | 3 ++- service/ControlPlane.cpp | 3 ++- 9 files changed, 111 insertions(+), 22 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 2c141f47..5b478afb 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -179,6 +179,11 @@ extern "C" { */ #define ZT_CLUSTER_MAX_MESSAGE_LENGTH (1500 - 48) +/** + * Maximum value for link quality (min is 0) + */ +#define ZT_PATH_LINK_QUALITY_MAX 0xff + /** * Packet characteristics flag: packet direction, 1 if inbound 0 if outbound */ @@ -1036,6 +1041,11 @@ typedef struct */ uint64_t trustedPathId; + /** + * Path link quality from 0 to 255 (always 255 if peer does not support) + */ + int linkQuality; + /** * Is path expired? */ diff --git a/node/Node.cpp b/node/Node.cpp index 35940d27..a75a56b4 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -401,9 +401,10 @@ ZT_PeerList *Node::peers() const memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); p->paths[p->pathCount].lastSend = path->first->lastOut(); p->paths[p->pathCount].lastReceive = path->first->lastIn(); + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); + p->paths[p->pathCount].linkQuality = (int)path->first->linkQuality(); p->paths[p->pathCount].expired = path->second; p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); ++p->pathCount; } } diff --git a/node/Packet.hpp b/node/Packet.hpp index 2017ce8e..d5817708 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -59,15 +59,17 @@ * + Otherwise backward compatible with protocol v4 * 6 - 1.1.5 ... 1.1.10 * + Network configuration format revisions including binary values - * 7 - 1.1.10 -- 1.2.0 + * 7 - 1.1.10 ... 1.1.17 * + Introduce trusted paths for local SDN use - * 8 - 1.2.0 -- CURRENT + * 8 - 1.1.17 ... 1.2.0 * + Multipart network configurations for large network configs * + Tags and Capabilities * + Inline push of CertificateOfMembership deprecated * + Certificates of representation for federation and mesh + * 9 - 1.2.0 ... CURRENT + * + In-band encoding of packet counter for link quality measurement */ -#define ZT_PROTO_VERSION 8 +#define ZT_PROTO_VERSION 9 /** * Minimum supported protocol version @@ -1319,6 +1321,11 @@ public: */ inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } + /** + * @return Value of link quality counter extracted from this packet's ID, range 0 to 7 (3 bits) + */ + inline unsigned int linkQualityCounter() const { return (unsigned int)(reinterpret_cast(data())[7] & 7); } + /** * Set packet verb * diff --git a/node/Path.hpp b/node/Path.hpp index 626f2f4f..dd6455d1 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -30,6 +31,7 @@ #include "SharedPtr.hpp" #include "AtomicCounter.hpp" #include "NonCopyable.hpp" +#include "Utils.hpp" /** * Maximum return value of preferenceRank() @@ -105,22 +107,34 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), + _incomingLinkQualityFastLog(0xffffffffffffffffULL), + _incomingLinkQualitySlowLogPtr(0), + _incomingLinkQualitySlowLogCounter(-64), // discard first fast log + _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) { + for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) + _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } Path(const InetAddress &localAddress,const InetAddress &addr) : _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), + _incomingLinkQualityFastLog(0xffffffffffffffffULL), + _incomingLinkQualitySlowLogPtr(0), + _incomingLinkQualitySlowLogCounter(-64), // discard first fast log + _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) { + for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) + _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } /** @@ -130,6 +144,39 @@ public: */ inline void received(const uint64_t t) { _lastIn = t; } + /** + * Update link quality using a counter from an incoming packet (or packet head in fragmented case) + * + * @param counter Packet link quality counter (range 0 to 7, must not have other bits set) + */ + inline void updateLinkQuality(const unsigned int counter) + { + const unsigned int prev = _incomingLinkQualityPreviousPacketCounter; + _incomingLinkQualityPreviousPacketCounter = counter; + const uint64_t fl = (_incomingLinkQualityFastLog = ((_incomingLinkQualityFastLog << 1) | (uint64_t)(prev == ((counter - 1) & 0x7)))); + if (++_incomingLinkQualitySlowLogCounter >= 64) { + _incomingLinkQualitySlowLogCounter = 0; + _incomingLinkQualitySlowLog[_incomingLinkQualitySlowLogPtr++ % sizeof(_incomingLinkQualitySlowLog)] = Utils::countBits(fl); + } + } + + /** + * @return Link quality from 0 (min) to 255 (max) + */ + inline unsigned int linkQuality() const + { + unsigned long slsize = _incomingLinkQualitySlowLogPtr; + if (slsize > (unsigned long)sizeof(_incomingLinkQualitySlowLog)) + slsize = (unsigned long)sizeof(_incomingLinkQualitySlowLog); + else if (!slsize) + return 255; // ZT_PATH_LINK_QUALITY_MAX + unsigned long lq = 0; + for(unsigned long i=0;i= 255) ? 255 : lq); + } + /** * Set time last trusted packet was received (done in Peer::received()) */ @@ -251,13 +298,18 @@ public: inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } private: - uint64_t _lastOut; - uint64_t _lastIn; - uint64_t _lastTrustEstablishedPacketReceived; - unsigned int _outgoingPacketCounter; + volatile uint64_t _lastOut; + volatile uint64_t _lastIn; + volatile uint64_t _lastTrustEstablishedPacketReceived; + volatile uint64_t _incomingLinkQualityFastLog; + volatile unsigned long _incomingLinkQualitySlowLogPtr; + volatile signed int _incomingLinkQualitySlowLogCounter; + volatile unsigned int _incomingLinkQualityPreviousPacketCounter; + volatile unsigned int _outgoingPacketCounter; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often + volatile uint8_t _incomingLinkQualitySlowLog[32]; AtomicCounter __refCount; }; diff --git a/node/Peer.cpp b/node/Peer.cpp index c4c8774e..1dde8b65 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -142,6 +142,9 @@ void Peer::received( } if (hops == 0) { + if (_vProto >= 9) + path->updateLinkQuality((unsigned int)(packetId & 7)); + bool pathIsConfirmed = false; { Mutex::Lock _l(_paths_m); diff --git a/node/Switch.cpp b/node/Switch.cpp index bf309e36..0392aec1 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -185,17 +185,6 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important! // Handle packet head ------------------------------------------------- - // See packet format in Packet.hpp to understand this - const uint64_t packetId = ( - (((uint64_t)reinterpret_cast(data)[0]) << 56) | - (((uint64_t)reinterpret_cast(data)[1]) << 48) | - (((uint64_t)reinterpret_cast(data)[2]) << 40) | - (((uint64_t)reinterpret_cast(data)[3]) << 32) | - (((uint64_t)reinterpret_cast(data)[4]) << 24) | - (((uint64_t)reinterpret_cast(data)[5]) << 16) | - (((uint64_t)reinterpret_cast(data)[6]) << 8) | - ((uint64_t)reinterpret_cast(data)[7]) - ); const Address destination(reinterpret_cast(data) + 8,ZT_ADDRESS_LENGTH); const Address source(reinterpret_cast(data) + 13,ZT_ADDRESS_LENGTH); @@ -297,6 +286,17 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { // Packet is the head of a fragmented packet series + const uint64_t packetId = ( + (((uint64_t)reinterpret_cast(data)[0]) << 56) | + (((uint64_t)reinterpret_cast(data)[1]) << 48) | + (((uint64_t)reinterpret_cast(data)[2]) << 40) | + (((uint64_t)reinterpret_cast(data)[3]) << 32) | + (((uint64_t)reinterpret_cast(data)[4]) << 24) | + (((uint64_t)reinterpret_cast(data)[5]) << 16) | + (((uint64_t)reinterpret_cast(data)[6]) << 8) | + ((uint64_t)reinterpret_cast(data)[7]) + ); + Mutex::Lock _l(_rxQueue_m); RXQueueEntry *const rq = _findRXQueueEntry(now,packetId); @@ -344,7 +344,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from rq = tmp; } rq->timestamp = now; - rq->packetId = packetId; + rq->packetId = packet.packetId(); rq->frag0 = packet; rq->totalFragments = 1; rq->haveFragments = 1; diff --git a/node/Utils.hpp b/node/Utils.hpp index 7b1994be..ceb29d7e 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -252,6 +252,20 @@ public: return ((((v + (v >> 4)) & (uint32_t)0xF0F0F0F) * (uint32_t)0x1010101) >> 24); } + /** + * Count the number of bits set in an integer + * + * @param v 64-bit integer + * @return Number of bits set in this integer (0-64) + */ + static inline uint64_t countBits(uint64_t v) + { + v = v - ((v >> 1) & (uint64_t)~(uint64_t)0/3); + v = (v & (uint64_t)~(uint64_t)0/15*3) + ((v >> 2) & (uint64_t)~(uint64_t)0/15*3); + v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0/255*15; + return (uint64_t)(v * ((uint64_t)~(uint64_t)0/255)) >> 56; + } + /** * Check if a memory buffer is all-zero * diff --git a/one.cpp b/one.cpp index 3649c18c..8f116aa0 100644 --- a/one.cpp +++ b/one.cpp @@ -355,7 +355,8 @@ static int cli(int argc,char **argv) char tmp[256]; std::string addr = path["address"]; const uint64_t now = OSUtils::now(); - Utils::snprintf(tmp,sizeof(tmp),"%s;%llu;%llu",addr.c_str(),now - (uint64_t)path["lastSend"],now - (uint64_t)path["lastReceive"]); + const double lq = (path.count("linkQuality")) ? (double)path["linkQuality"] : -1.0; + Utils::snprintf(tmp,sizeof(tmp),"%s;%llu;%llu;%1.2f",addr.c_str(),now - (uint64_t)path["lastSend"],now - (uint64_t)path["lastReceive"],lq); bestPath = tmp; break; } diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 9ba001ea..e995a4a5 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -127,10 +127,11 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) j["address"] = reinterpret_cast(&(peer->paths[i].address))->toString(); j["lastSend"] = peer->paths[i].lastSend; j["lastReceive"] = peer->paths[i].lastReceive; + j["trustedPathId"] = peer->paths[i].trustedPathId; + j["linkQuality"] = (double)peer->paths[i].linkQuality / (double)ZT_PATH_LINK_QUALITY_MAX; j["active"] = (bool)(peer->paths[i].expired == 0); j["expired"] = (bool)(peer->paths[i].expired != 0); j["preferred"] = (bool)(peer->paths[i].preferred != 0); - j["trustedPathId"] = peer->paths[i].trustedPathId; pa.push_back(j); } pj["paths"] = pa; -- cgit v1.2.3 From a577b8d3816069a448a946302048a377b55cd74a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 1 Mar 2017 16:33:34 -0800 Subject: Update how controller handles circuit tests -- save results to filesystem. --- controller/EmbeddedNetworkController.cpp | 137 +++++++++++++++---------------- controller/EmbeddedNetworkController.hpp | 15 ++-- controller/JSONDB.cpp | 25 ++++-- controller/JSONDB.hpp | 6 +- controller/README.md | 11 +-- node/Peer.cpp | 6 +- service/OneService.cpp | 2 +- 7 files changed, 100 insertions(+), 102 deletions(-) (limited to 'node/Peer.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 0e57fc14..7915765b 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -428,9 +428,9 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) return false; } -EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPath,FILE *feed) : +EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPath) : _threadsStarted(false), - _db(dbPath,feed), + _db(dbPath), _node(node) { OSUtils::mkdir(dbPath); @@ -546,21 +546,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( return 200; } - } else if ((path[2] == "test")&&(path.size() >= 4)) { - - Mutex::Lock _l(_circuitTests_m); - std::map< uint64_t,_CircuitTestEntry >::iterator cte(_circuitTests.find(Utils::hexStrToU64(path[3].c_str()))); - if ((cte != _circuitTests.end())&&(cte->second.test)) { - - responseBody = "["; - responseBody.append(cte->second.jsonResults); - responseBody.push_back(']'); - responseContentType = "application/json"; - - return 200; - - } // else 404 - } // else 404 } else { @@ -755,9 +740,10 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( return 200; } else if ((path.size() == 3)&&(path[2] == "test")) { - Mutex::Lock _l(_circuitTests_m); + Mutex::Lock _l(_tests_m); - ZT_CircuitTest *test = (ZT_CircuitTest *)malloc(sizeof(ZT_CircuitTest)); + _tests.push_back(ZT_CircuitTest()); + ZT_CircuitTest *const test = &(_tests.back()); memset(test,0,sizeof(ZT_CircuitTest)); Utils::getSecureRandom(&(test->testId),sizeof(test->testId)); @@ -781,7 +767,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( test->reportAtEveryHop = (OSUtils::jsonBool(b["reportAtEveryHop"],true) ? 1 : 0); if (!test->hopCount) { - ::free((void *)test); + _tests.pop_back(); responseBody = "{ \"message\": \"a test must contain at least one hop\" }"; responseContentType = "application/json"; return 400; @@ -789,18 +775,18 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( test->timestamp = OSUtils::now(); - _CircuitTestEntry &te = _circuitTests[test->testId]; - te.test = test; - te.jsonResults = ""; - - if (_node) + if (_node) { _node->circuitTestBegin(test,&(EmbeddedNetworkController::_circuitTestCallback)); - else return 500; + } else { + _tests.pop_back(); + return 500; + } char json[1024]; Utils::snprintf(json,sizeof(json),"{\"testId\":\"%.16llx\"}",test->testId); responseBody = json; responseContentType = "application/json"; + return 200; } // else 404 @@ -1137,62 +1123,67 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( void EmbeddedNetworkController::threadMain() throw() { + uint64_t lastCircuitTestCheck = 0; for(;;) { - _RQEntry *const qe = _queue.get(); + _RQEntry *const qe = _queue.get(); // waits on next request if (!qe) break; // enqueue a NULL to terminate threads try { _request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); } catch ( ... ) {} delete qe; + + uint64_t now = OSUtils::now(); + if ((now - lastCircuitTestCheck) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { + lastCircuitTestCheck = now; + Mutex::Lock _l(_tests_m); + for(std::list< ZT_CircuitTest >::iterator i(_tests.begin());i!=_tests.end();) { + if ((now - i->timestamp) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) { + _node->circuitTestEnd(&(*i)); + _tests.erase(i++); + } else ++i; + } + } } } void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) { - char tmp[65535]; + char tmp[1024],id[128]; EmbeddedNetworkController *const self = reinterpret_cast(test->ptr); - if (!test) - return; - if (!report) - return; - - Mutex::Lock _l(self->_circuitTests_m); - std::map< uint64_t,_CircuitTestEntry >::iterator cte(self->_circuitTests.find(test->testId)); - - if (cte == self->_circuitTests.end()) { // sanity check: a circuit test we didn't launch? - self->_node->circuitTestEnd(test); - ::free((void *)test); - return; - } + if ((!test)||(!report)||(!test->credentialNetworkId)) return; // sanity check + const uint64_t now = OSUtils::now(); + Utils::snprintf(id,sizeof(id),"network/%.16llx/test/%.16llx-%.16llx-%.10llx-%.10llx",test->credentialNetworkId,test->testId,now,report->upstream,report->current); Utils::snprintf(tmp,sizeof(tmp), - "%s{\n" - "\t\"timestamp\": %llu," ZT_EOL_S - "\t\"testId\": \"%.16llx\"," ZT_EOL_S - "\t\"upstream\": \"%.10llx\"," ZT_EOL_S - "\t\"current\": \"%.10llx\"," ZT_EOL_S - "\t\"receivedTimestamp\": %llu," ZT_EOL_S - "\t\"sourcePacketId\": \"%.16llx\"," ZT_EOL_S - "\t\"flags\": %llu," ZT_EOL_S - "\t\"sourcePacketHopCount\": %u," ZT_EOL_S - "\t\"errorCode\": %u," ZT_EOL_S - "\t\"vendor\": %d," ZT_EOL_S - "\t\"protocolVersion\": %u," ZT_EOL_S - "\t\"majorVersion\": %u," ZT_EOL_S - "\t\"minorVersion\": %u," ZT_EOL_S - "\t\"revision\": %u," ZT_EOL_S - "\t\"platform\": %d," ZT_EOL_S - "\t\"architecture\": %d," ZT_EOL_S - "\t\"receivedOnLocalAddress\": \"%s\"," ZT_EOL_S - "\t\"receivedFromRemoteAddress\": \"%s\"" ZT_EOL_S - "}", - ((cte->second.jsonResults.length() > 0) ? ",\n" : ""), - (unsigned long long)report->timestamp, + "{\"id\": \"%s\"," + "\"timestamp\": %llu," + "\"networkId\": \"%.16llx\"," + "\"testId\": \"%.16llx\"," + "\"upstream\": \"%.10llx\"," + "\"current\": \"%.10llx\"," + "\"receivedTimestamp\": %llu," + "\"sourcePacketId\": \"%.16llx\"," + "\"flags\": %llu," + "\"sourcePacketHopCount\": %u," + "\"errorCode\": %u," + "\"vendor\": %d," + "\"protocolVersion\": %u," + "\"majorVersion\": %u," + "\"minorVersion\": %u," + "\"revision\": %u," + "\"platform\": %d," + "\"architecture\": %d," + "\"receivedOnLocalAddress\": \"%s\"," + "\"receivedFromRemoteAddress\": \"%s\"," + "\"receivedFromLinkQuality\": %f}", + id + 30, // last bit only, not leading path + (unsigned long long)test->timestamp, + (unsigned long long)test->credentialNetworkId, (unsigned long long)test->testId, (unsigned long long)report->upstream, (unsigned long long)report->current, - (unsigned long long)OSUtils::now(), + (unsigned long long)now, (unsigned long long)report->sourcePacketId, (unsigned long long)report->flags, report->sourcePacketHopCount, @@ -1205,9 +1196,11 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes (int)report->platform, (int)report->architecture, reinterpret_cast(&(report->receivedOnLocalAddress))->toString().c_str(), - reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str()); + reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str(), + ((double)report->receivedFromLinkQuality / (double)ZT_PATH_LINK_QUALITY_MAX)); - cte->second.jsonResults.append(tmp); + Mutex::Lock _l(self->_db_m); + self->_db.writeRaw(id,std::string(tmp)); } void EmbeddedNetworkController::_request( @@ -1354,12 +1347,12 @@ void EmbeddedNetworkController::_request( if (requestPacketId) { // only log if this is a request, not for generated pushes json rlEntry = json::object(); rlEntry["ts"] = now; - rlEntry["authorized"] = (authorizedBy) ? true : false; - rlEntry["authorizedBy"] = (authorizedBy) ? authorizedBy : ""; - rlEntry["clientMajorVersion"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); - rlEntry["clientMinorVersion"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); - rlEntry["clientRevision"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); - rlEntry["clientProtocolVersion"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0); + rlEntry["auth"] = (authorizedBy) ? true : false; + rlEntry["authBy"] = (authorizedBy) ? authorizedBy : ""; + rlEntry["vMajor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); + rlEntry["vMinor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); + rlEntry["vRev"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); + rlEntry["vProto"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0); if (fromAddr) rlEntry["fromAddr"] = fromAddr.toString(); diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 3e39eaf5..ab7cdd53 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -46,6 +46,9 @@ // Number of background threads to start -- not actually started until needed #define ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT 2 +// TTL for circuit tests +#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000 + namespace ZeroTier { class Node; @@ -56,9 +59,8 @@ public: /** * @param node Parent node * @param dbPath Path to store data - * @param feed FILE to send feed of all data and changes to (zero-delimited JSON objects) or NULL for none */ - EmbeddedNetworkController(Node *node,const char *dbPath,FILE *feed); + EmbeddedNetworkController(Node *node,const char *dbPath); virtual ~EmbeddedNetworkController(); virtual void init(const Identity &signingId,Sender *sender); @@ -199,13 +201,8 @@ private: NetworkController::Sender *_sender; Identity _signingId; - struct _CircuitTestEntry - { - ZT_CircuitTest *test; - std::string jsonResults; - }; - std::map< uint64_t,_CircuitTestEntry > _circuitTests; - Mutex _circuitTests_m; + std::list< ZT_CircuitTest > _tests; + Mutex _tests_m; std::map< std::pair,uint64_t > _lastRequestTime; Mutex _lastRequestTime_m; diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index 044f791c..1277aabb 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -22,6 +22,22 @@ namespace ZeroTier { static const nlohmann::json _EMPTY_JSON(nlohmann::json::object()); +bool JSONDB::writeRaw(const std::string &n,const std::string &obj) +{ + if (!_isValidObjectName(n)) + return false; + + const std::string path(_genPath(n,true)); + if (!path.length()) + return false; + + const std::string buf(obj); + if (!OSUtils::writeFile(path.c_str(),buf)) + return false; + + return true; +} + bool JSONDB::put(const std::string &n,const nlohmann::json &obj) { if (!_isValidObjectName(n)) @@ -35,9 +51,6 @@ bool JSONDB::put(const std::string &n,const nlohmann::json &obj) if (!OSUtils::writeFile(path.c_str(),buf)) return false; - if (_feed) - fwrite(buf.c_str(),buf.length()+1,1,_feed); - _E &e = _db[n]; e.obj = obj; e.lastModifiedOnDisk = OSUtils::getLastModified(path.c_str()); @@ -72,9 +85,6 @@ const nlohmann::json &JSONDB::get(const std::string &n,unsigned long maxSinceChe e->second.obj = OSUtils::jsonParse(buf); e->second.lastModifiedOnDisk = lm; // don't update these if there is a parse error -- try again and again ASAP e->second.lastCheck = now; - - if (_feed) - fwrite(buf.c_str(),buf.length()+1,1,_feed); // it changed, so send to feed (also sends all objects on startup, which we want for Central) } catch ( ... ) {} // parse errors result in "holding pattern" behavior } } @@ -99,9 +109,6 @@ const nlohmann::json &JSONDB::get(const std::string &n,unsigned long maxSinceChe e2.lastModifiedOnDisk = lm; e2.lastCheck = now; - if (_feed) - fwrite(buf.c_str(),buf.length()+1,1,_feed); - return e2.obj; } } diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index 40113655..5b7c5e50 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -42,8 +42,7 @@ namespace ZeroTier { class JSONDB { public: - JSONDB(const std::string &basePath,FILE *feed) : - _feed(feed), + JSONDB(const std::string &basePath) : _basePath(basePath) { _reload(_basePath); @@ -55,6 +54,8 @@ public: _reload(_basePath); } + bool writeRaw(const std::string &n,const std::string &obj); + bool put(const std::string &n,const nlohmann::json &obj); inline bool put(const std::string &n1,const std::string &n2,const nlohmann::json &obj) { return this->put((n1 + "/" + n2),obj); } @@ -108,7 +109,6 @@ private: inline bool operator!=(const _E &e) const { return (obj != e.obj); } }; - FILE *_feed; std::string _basePath; std::map _db; }; diff --git a/controller/README.md b/controller/README.md index 093300a6..db8d0153 100644 --- a/controller/README.md +++ b/controller/README.md @@ -237,11 +237,12 @@ Note that managed IP assignments are only used if they fall within a managed rou | Field | Type | Description | | --------------------- | ------------- | ------------------------------------------------- | | ts | integer | Time of request, ms since epoch | -| authorized | boolean | Was member authorized? | -| clientMajorVersion | integer | Client major version or -1 if unknown | -| clientMinorVersion | integer | Client minor version or -1 if unknown | -| clientRevision | integer | Client revision or -1 if unknown | -| clientProtocolVersion | integer | ZeroTier protocol version reported by client | +| auth | boolean | Was member authorized? | +| authBy | string | How was member authorized? | +| vMajor | integer | Client major version or -1 if unknown | +| vMinor | integer | Client minor version or -1 if unknown | +| vRev | integer | Client revision or -1 if unknown | +| vProto | integer | ZeroTier protocol version reported by client | | fromAddr | string | Physical address if known | The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead. diff --git a/node/Peer.cpp b/node/Peer.cpp index 1dde8b65..fa3ce6c8 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -141,10 +141,10 @@ void Peer::received( path->trustedPacketReceived(now); } - if (hops == 0) { - if (_vProto >= 9) - path->updateLinkQuality((unsigned int)(packetId & 7)); + if (_vProto >= 9) + path->updateLinkQuality((unsigned int)(packetId & 7)); + if (hops == 0) { bool pathIsConfirmed = false; { Mutex::Lock _l(_paths_m); diff --git a/service/OneService.cpp b/service/OneService.cpp index 81950e26..8d8856a2 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -638,7 +638,7 @@ public: return _termReason; } - _controller = new EmbeddedNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S ZT_CONTROLLER_DB_PATH).c_str(),(FILE *)0); + _controller = new EmbeddedNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S ZT_CONTROLLER_DB_PATH).c_str()); _node->setNetconfMaster((void *)_controller); #ifdef ZT_ENABLE_CLUSTER -- cgit v1.2.3 From e4896b257fde05a216500804d9bcef3b84b0980e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Mar 2017 17:03:17 -0700 Subject: Add thread PTR that gets passed through the entire ZT core call stack and then passed to handler functions resulting from a call. --- controller/EmbeddedNetworkController.cpp | 2 +- include/ZeroTierOne.h | 51 ++++-- node/Capability.cpp | 6 +- node/Capability.hpp | 2 +- node/CertificateOfMembership.cpp | 6 +- node/CertificateOfMembership.hpp | 3 +- node/CertificateOfOwnership.cpp | 6 +- node/CertificateOfOwnership.hpp | 3 +- node/IncomingPacket.cpp | 294 +++++++++++++++---------------- node/IncomingPacket.hpp | 43 ++--- node/Membership.cpp | 24 +-- node/Membership.hpp | 13 +- node/Multicaster.cpp | 23 +-- node/Multicaster.hpp | 13 +- node/Network.cpp | 112 ++++++------ node/Network.hpp | 59 ++++--- node/Node.cpp | 136 +++++++------- node/Node.hpp | 42 +++-- node/OutboundMulticast.cpp | 6 +- node/OutboundMulticast.hpp | 13 +- node/Path.cpp | 4 +- node/Path.hpp | 3 +- node/Peer.cpp | 37 ++-- node/Peer.hpp | 22 ++- node/Revocation.cpp | 6 +- node/Revocation.hpp | 3 +- node/SelfAwareness.cpp | 10 +- node/SelfAwareness.hpp | 2 +- node/Switch.cpp | 97 +++++----- node/Switch.hpp | 22 ++- node/Tag.cpp | 6 +- node/Tag.hpp | 3 +- node/Topology.cpp | 54 +++--- node/Topology.hpp | 26 +-- osdep/BSDEthernetTap.cpp | 5 +- osdep/BSDEthernetTap.hpp | 4 +- osdep/LinuxEthernetTap.cpp | 4 +- osdep/LinuxEthernetTap.hpp | 4 +- osdep/OSXEthernetTap.cpp | 4 +- osdep/OSXEthernetTap.hpp | 4 +- osdep/WindowsEthernetTap.cpp | 5 +- osdep/WindowsEthernetTap.hpp | 4 +- service/OneService.cpp | 58 +++--- service/SoftwareUpdater.cpp | 12 +- 44 files changed, 673 insertions(+), 583 deletions(-) (limited to 'node/Peer.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 51500ed7..ce56e906 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -790,7 +790,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( test->timestamp = OSUtils::now(); if (_node) { - _node->circuitTestBegin(test,&(EmbeddedNetworkController::_circuitTestCallback)); + _node->circuitTestBegin((void *)0,test,&(EmbeddedNetworkController::_circuitTestCallback)); } else { _tests.pop_back(); return 500; diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 98413a21..747e1855 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1408,6 +1408,7 @@ typedef void ZT_Node; typedef int (*ZT_VirtualNetworkConfigFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* Network ID */ void **, /* Modifiable network user PTR */ enum ZT_VirtualNetworkConfigOperation, /* Config operation */ @@ -1423,6 +1424,7 @@ typedef int (*ZT_VirtualNetworkConfigFunction)( typedef void (*ZT_VirtualNetworkFrameFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* Network ID */ void **, /* Modifiable network user PTR */ uint64_t, /* Source MAC */ @@ -1442,10 +1444,11 @@ typedef void (*ZT_VirtualNetworkFrameFunction)( * in the definition of ZT_Event. */ typedef void (*ZT_EventCallback)( - ZT_Node *, - void *, - enum ZT_Event, - const void *); + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + enum ZT_Event, /* Event type */ + const void *); /* Event payload (if applicable) */ /** * Function to get an object from the data store @@ -1468,8 +1471,9 @@ typedef void (*ZT_EventCallback)( * object. */ typedef long (*ZT_DataStoreGetFunction)( - ZT_Node *, - void *, + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ const char *, void *, unsigned long, @@ -1495,6 +1499,7 @@ typedef long (*ZT_DataStoreGetFunction)( typedef int (*ZT_DataStorePutFunction)( ZT_Node *, void *, + void *, /* Thread ptr */ const char *, const void *, unsigned long, @@ -1529,6 +1534,7 @@ typedef int (*ZT_DataStorePutFunction)( typedef int (*ZT_WirePacketSendFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ const struct sockaddr_storage *, /* Local address */ const struct sockaddr_storage *, /* Remote address */ const void *, /* Packet data */ @@ -1562,6 +1568,7 @@ typedef int (*ZT_WirePacketSendFunction)( typedef int (*ZT_PathCheckFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* ZeroTier address */ const struct sockaddr_storage *, /* Local address */ const struct sockaddr_storage *); /* Remote address */ @@ -1584,6 +1591,7 @@ typedef int (*ZT_PathCheckFunction)( typedef int (*ZT_PathLookupFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ + void *, /* Thread ptr */ uint64_t, /* ZeroTier address (40 bits) */ int, /* Desired ss_family or -1 for any */ struct sockaddr_storage *); /* Result buffer */ @@ -1654,11 +1662,12 @@ struct ZT_Node_Callbacks * * @param node Result: pointer is set to new node instance on success * @param uptr User pointer to pass to functions/callbacks + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param callbacks Callback function configuration * @param now Current clock in milliseconds * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); /** * Delete a node and free all resources it consumes @@ -1674,6 +1683,7 @@ void ZT_Node_delete(ZT_Node *node); * Process a packet received from the physical wire * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds * @param localAddress Local address, or point to ZT_SOCKADDR_NULL if unspecified * @param remoteAddress Origin of packet @@ -1684,6 +1694,7 @@ void ZT_Node_delete(ZT_Node *node); */ enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -1695,6 +1706,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( * Process a frame from a virtual network port (tap) * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds * @param nwid ZeroTier 64-bit virtual network ID * @param sourceMac Source MAC address (least significant 48 bits) @@ -1708,6 +1720,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( */ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -1722,11 +1735,12 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( * Perform periodic background operations * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); /** * Join a network @@ -1742,7 +1756,7 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol * @param uptr An arbitrary pointer to associate with this network (default: NULL) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr); +enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); /** * Leave a network @@ -1759,7 +1773,7 @@ enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr); * @param uptr Target pointer is set to uptr (if not NULL) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr); +enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr); /** * Subscribe to an Ethernet multicast group @@ -1781,12 +1795,13 @@ enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr); * This does not generate an update call to networkConfigCallback(). * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param nwid 64-bit network ID * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); +enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); /** * Unsubscribe from an Ethernet multicast group (or all groups) @@ -1811,21 +1826,24 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint * across invocations if the contents of moon.d are scanned and orbit is * called for each on startup. * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param moonWorldId Moon's world ID * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition * @param len Length of moonWorld in bytes * @return Error if moon was invalid or failed to be added */ -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId,uint64_t moonSeed); +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed); /** * Remove a moon (does nothing if not present) * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param moonWorldId World ID of moon to remove * @return Error if anything bad happened */ -enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId); +enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId); /** * Get this node's 40-bit ZeroTier address @@ -1919,13 +1937,15 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); * There is no delivery guarantee here. Failure can occur if the message is * too large or if dest is not a valid ZeroTier address. * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param dest Destination ZeroTier address * @param typeId VERB_USER_MESSAGE type ID * @param data Payload data to attach to user message * @param len Length of data in bytes * @return Boolean: non-zero on success, zero on failure */ -int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); +int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); /** * Set a network configuration master instance for this node @@ -1957,11 +1977,12 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); * for results forever. * * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param test Test configuration * @param reportCallback Function to call each time a report is received * @return OK or error if, for example, test is too big for a packet or support isn't compiled in */ -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); +enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *)); /** * Stop listening for results to a given circuit test diff --git a/node/Capability.cpp b/node/Capability.cpp index 0a736ca8..c178e566 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -25,7 +25,7 @@ namespace ZeroTier { -int Capability::verify(const RuntimeEnvironment *RR) const +int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const { try { // There must be at least one entry, and sanity check for bad chain max length @@ -46,12 +46,12 @@ int Capability::verify(const RuntimeEnvironment *RR) const return -1; // otherwise if we have another entry it must be from the previous holder in the chain } - const Identity id(RR->topology->getIdentity(_custody[c].from)); + const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from)); if (id) { if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) return -1; } else { - RR->sw->requestWhois(_custody[c].from); + RR->sw->requestWhois(tPtr,_custody[c].from); return 1; } } diff --git a/node/Capability.hpp b/node/Capability.hpp index d070f2ad..5ef6c994 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -161,7 +161,7 @@ public: * @param RR Runtime environment to provide for peer lookup, etc. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 43efcd20..9bf70216 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -207,14 +207,14 @@ bool CertificateOfMembership::sign(const Identity &with) } } -int CertificateOfMembership::verify(const RuntimeEnvironment *RR) const +int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 2d7c2cb3..ae976b50 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -250,9 +250,10 @@ public: * Verify this COM and its signature * * @param RR Runtime environment for looking up peers + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; /** * @return True if signed diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 6fc59ad1..2bd181e0 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -25,13 +25,13 @@ namespace ZeroTier { -int CertificateOfOwnership::verify(const RuntimeEnvironment *RR) const +int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } try { diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 57fd8259..8c47582d 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -137,9 +137,10 @@ public: /** * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template inline void serialize(Buffer &b,const bool forSign = false) const diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e2275a04..52794fd7 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -44,7 +44,7 @@ namespace ZeroTier { -bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) +bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) { const Address sourceAddress(source()); @@ -65,10 +65,10 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { // Only HELLO is allowed in the clear, but will still have a MAC - return _doHELLO(RR,false); + return _doHELLO(RR,tPtr,false); } - const SharedPtr peer(RR->topology->getPeer(sourceAddress)); + const SharedPtr peer(RR->topology->getPeer(tPtr,sourceAddress)); if (peer) { if (!trusted) { if (!dearmor(peer->key())) { @@ -89,30 +89,30 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); return true; - case Packet::VERB_HELLO: return _doHELLO(RR,true); - case Packet::VERB_ERROR: return _doERROR(RR,peer); - case Packet::VERB_OK: return _doOK(RR,peer); - case Packet::VERB_WHOIS: return _doWHOIS(RR,peer); - case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer); - case Packet::VERB_FRAME: return _doFRAME(RR,peer); - 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_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer); - case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer); - case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,peer); - case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); - case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); - case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); - case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); - case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); - case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,peer); + case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true); + case Packet::VERB_ERROR: return _doERROR(RR,tPtr,peer); + case Packet::VERB_OK: return _doOK(RR,tPtr,peer); + case Packet::VERB_WHOIS: return _doWHOIS(RR,tPtr,peer); + case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,tPtr,peer); + case Packet::VERB_FRAME: return _doFRAME(RR,tPtr,peer); + case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,tPtr,peer); + case Packet::VERB_ECHO: return _doECHO(RR,tPtr,peer); + case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,tPtr,peer); + case Packet::VERB_NETWORK_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,tPtr,peer); + case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,tPtr,peer); + case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,tPtr,peer); + case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer); + case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer); + case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer); + case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,tPtr,peer); + case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,tPtr,peer); + case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer); } } else { - RR->sw->requestWhois(sourceAddress); + RR->sw->requestWhois(tPtr,sourceAddress); return false; } } catch ( ... ) { @@ -123,7 +123,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) } } -bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; @@ -163,7 +163,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_IDENTITY_COLLISION: // FIXME: for federation this will need a payload with a signature or something. if (RR->topology->isUpstream(peer->identity())) - RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); + RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { @@ -171,7 +171,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) - network->pushCredentialsNow(peer->address(),now); + network->pushCredentialsNow(tPtr,peer->address(),now); } break; case Packet::ERROR_NETWORK_ACCESS_DENIED_: { @@ -185,7 +185,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->gate(peer))) { + if ((network)&&(network->gate(tPtr,peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); @@ -195,14 +195,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated) +bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) { try { const uint64_t now = RR->node->now(); @@ -226,7 +226,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } - SharedPtr peer(RR->topology->getPeer(id.address())); + SharedPtr peer(RR->topology->getPeer(tPtr,id.address())); if (peer) { // We already have an identity with this address -- check for collisions if (!alreadyAuthenticated) { @@ -246,7 +246,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.append((uint64_t)pid); outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); } @@ -292,7 +292,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut return true; } - peer = RR->topology->addPeer(newPeer); + peer = RR->topology->addPeer(tPtr,newPeer); // Continue at // VALID } @@ -304,7 +304,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut if (ptr < size()) { ptr += externalSurfaceAddress.deserialize(*this,ptr); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + RR->sa->iam(tPtr,id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); } // Get primary planet world ID and world timestamp if present @@ -408,17 +408,17 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),now); + _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; @@ -463,7 +463,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p while (ptr < endOfWorlds) { World w; ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(w,false); + RR->topology->addWorld(tPtr,w,false); } } else { ptr += worldsLen; @@ -490,20 +490,20 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + RR->sa->iam(tPtr,peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: if (RR->topology->isUpstream(peer->identity())) { const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); - RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR,RR->identity,id)))); + RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); if (network) - network->handleConfigChunk(packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); + network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; case Packet::VERB_MULTICAST_GATHER: { @@ -513,7 +513,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } } break; @@ -532,7 +532,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); if (com) - network->addCredential(com); + network->addCredential(tPtr,com); } if ((flags & 0x02) != 0) { @@ -540,7 +540,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; unsigned int totalKnown = at(offset); offset += 4; unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -548,14 +548,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { @@ -573,13 +573,13 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; - const Identity id(RR->topology->getIdentity(addr)); + const Identity id(RR->topology->getIdentity(tPtr,addr)); if (id) { id.serialize(outp,false); ++count; } else { // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(addr); + RR->sw->requestWhois(tPtr,addr); #ifdef ZT_ENABLE_CLUSTER // Distribute WHOIS queries across a cluster if we do not know the ID. // This may result in duplicate OKs to the querying peer, which is fine. @@ -591,32 +591,32 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr if (count > 0) { outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (!RR->topology->isUpstream(peer->identity())) { TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); } else { const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(with)); + const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); if (rendezvousWith) { const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) { - RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false,0); + if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localAddress(),atAddr)) { + RR->node->putPacket(tPtr,_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(tPtr,_path->localAddress(),atAddr,RR->node->now(),false,0); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -628,46 +628,46 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); bool trustEstablished = false; if (network) { - if (network->gate(peer)) { + if (network->gate(tPtr,peer)) { trustEstablished = true; if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); const MAC sourceMac(peer->address(),nwid); const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) - RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) + RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } } else { TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } - peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); @@ -680,13 +680,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

addCredential(com); + network->addCredential(tPtr,com); } - if (!network->gate(peer)) { + if (!network->gate(tPtr,peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -699,36 +699,36 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

mac())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } - switch (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { + switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { case 1: if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } // fall through -- 2 means accept regardless of bridging checks or other restrictions case 2: - RR->node->putFrame(nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); + RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen); break; } } @@ -739,14 +739,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -754,7 +754,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&peer) +bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (!peer->rateGateEchoRequest(RR->node->now())) { @@ -769,16 +769,16 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t now = RR->node->now(); @@ -802,9 +802,9 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (!auth) { if ((!network)||(network->id() != nwid)) network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(peer))); + const bool authOnNet = ((network)&&(network->gate(tPtr,peer))); if (!authOnNet) - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); trustEstablished |= authOnNet; if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; @@ -815,18 +815,18 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (auth) { const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14)); - RR->mc->add(now,nwid,group,peer->address()); + RR->mc->add(tPtr,now,nwid,group,peer->address()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (!peer->rateGateCredentialsReceived(RR->node->now())) { @@ -847,7 +847,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S if (com) { const SharedPtr network(RR->node->network(com.networkId())); if (network) { - switch (network->addCredential(com)) { + switch (network->addCredential(tPtr,com)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -857,7 +857,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S case Membership::ADD_DEFERRED_FOR_WHOIS: return false; } - } else RR->mc->addCredential(com,false); + } else RR->mc->addCredential(tPtr,com,false); } } ++p; // skip trailing 0 after COMs if present @@ -868,7 +868,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += cap.deserialize(*this,p); const SharedPtr network(RR->node->network(cap.networkId())); if (network) { - switch (network->addCredential(cap)) { + switch (network->addCredential(tPtr,cap)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -888,7 +888,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += tag.deserialize(*this,p); const SharedPtr network(RR->node->network(tag.networkId())); if (network) { - switch (network->addCredential(tag)) { + switch (network->addCredential(tPtr,tag)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -908,7 +908,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += revocation.deserialize(*this,p); const SharedPtr network(RR->node->network(revocation.networkId())); if (network) { - switch(network->addCredential(peer->address(),revocation)) { + switch(network->addCredential(tPtr,peer->address(),revocation)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -928,7 +928,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S p += coo.deserialize(*this,p); const SharedPtr network(RR->node->network(coo.networkId())); if (network) { - switch(network->addCredential(coo)) { + switch(network->addCredential(tPtr,coo)) { case Membership::ADD_REJECTED: break; case Membership::ADD_ACCEPTED_NEW: @@ -942,7 +942,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); } catch (std::exception &exc) { //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -953,7 +953,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S return true; } -bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); @@ -972,10 +972,10 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); } catch (std::exception &exc) { //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); @@ -986,12 +986,12 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons return true; } -bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); if (network) { - const uint64_t configUpdateId = network->handleConfigChunk(packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); + const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); if (configUpdateId) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((uint8_t)Packet::VERB_ECHO); @@ -999,17 +999,17 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared outp.append((uint64_t)network->id()); outp.append((uint64_t)configUpdateId); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); @@ -1027,17 +1027,17 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); if (com) { if (network) - network->addCredential(com); - else RR->mc->addCredential(com,false); + network->addCredential(tPtr,com); + else RR->mc->addCredential(tPtr,com,false); } } catch ( ... ) { TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); } } - const bool trustEstablished = ((network)&&(network->gate(peer))); + const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); if (!trustEstablished) - _sendErrorNeedCredentials(RR,peer,nwid); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); @@ -1048,7 +1048,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); if (gatheredLocally > 0) { outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } // If we are a member of a cluster, distribute this GATHER across it @@ -1058,14 +1058,14 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar #endif } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); @@ -1081,19 +1081,19 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); if (com) - network->addCredential(com); + network->addCredential(tPtr,com); } - if (!network->gate(peer)) { + if (!network->gate(tPtr,peer)) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } if (network->config().multicastLimit == 0) { TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -1120,12 +1120,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if (!to.mac().isMulticast()) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -1134,14 +1134,14 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->learnBridgeRoute(from,peer->address()); } else { TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { - RR->node->putFrame(nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { + RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } } @@ -1155,14 +1155,14 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share outp.append((unsigned char)0x02); // flag 0x02 = contains gather results if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),RR->node->now()); + _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { - _sendErrorNeedCredentials(RR,peer,nwid); - peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1170,7 +1170,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share return true; } -bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const uint64_t now = RR->node->now(); @@ -1178,7 +1178,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1209,10 +1209,10 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1228,10 +1228,10 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha redundant = peer->hasActivePathTo(now,a); } - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) { + if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } @@ -1241,20 +1241,20 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha ptr += addrLen; } - peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - SharedPtr originator(RR->topology->getPeer(originatorAddress)); + SharedPtr originator(RR->topology->getPeer(tPtr,originatorAddress)); if (!originator) { - RR->sw->requestWhois(originatorAddress); + RR->sw->requestWhois(tPtr,originatorAddress); return false; } @@ -1285,7 +1285,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf); if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) { TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } vlf += signatureLength; @@ -1304,14 +1304,14 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr network(RR->node->network(originatorCredentialNetworkId)); if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } - if (network->gate(peer)) + if (network->gate(tPtr,peer)) reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } @@ -1327,7 +1327,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt for(unsigned int h=0;h nhp(RR->topology->getPeer(nextHop[h])); + SharedPtr nhp(RR->topology->getPeer(tPtr,nextHop[h])); if (nhp) { SharedPtr nhbp(nhp->getBestPath(now,false)); if ((nhbp)&&(nhbp->alive(now))) @@ -1362,7 +1362,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt nextHop[h].appendTo(outp); nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress } - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } // If there are next hops, forward the test along through the graph @@ -1377,19 +1377,19 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid outp.newInitializationVector(); outp.setDestination(nextHop[h]); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { ZT_CircuitTestReport report; @@ -1431,14 +1431,14 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S RR->node->postCircuitTestReport(&report); - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPtr &peer) +bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) { @@ -1447,16 +1447,16 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPt um.typeId = at(ZT_PACKET_IDX_PAYLOAD); um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); - RR->node->postEvent(ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); + RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } - peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } return true; } -void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) +void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) { const uint64_t now = RR->node->now(); if (peer->rateGateOutgoingComRequest(now)) { @@ -1466,7 +1466,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,cons outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); outp.armor(peer->key(),true,_path->nextOutgoingCounter()); - _path->send(RR,outp.data(),outp.size(),now); + _path->send(RR,tPtr,outp.data(),outp.size(),now); } } diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index febff28a..3d4a2e05 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -102,9 +102,10 @@ public: * may no longer be valid. * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return True if decoding and processing is complete, false if caller should try again */ - bool tryDecode(const RuntimeEnvironment *RR); + bool tryDecode(const RuntimeEnvironment *RR,void *tPtr); /** * @return Time of packet receipt / start of decode @@ -114,26 +115,26 @@ public: private: // These are called internally to handle packet contents once it has // been authenticated, decrypted, decompressed, and classified. - bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated); - bool _doOK(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); - bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,const SharedPtr &peer); - - void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); + bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated); + bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + + void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid); uint64_t _receiveTime; SharedPtr _path; diff --git a/node/Membership.cpp b/node/Membership.cpp index 3b2e3b1c..22c13c88 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -40,7 +40,7 @@ Membership::Membership() : for(unsigned int i=0;i= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) ); @@ -113,7 +113,7 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } @@ -123,7 +123,7 @@ const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) cons return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) { const uint64_t newts = com.timestamp().first; if (newts <= _comRevocationThreshold) { @@ -141,7 +141,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_ACCEPTED_REDUNDANT; } - switch(com.verify(RR)) { + switch(com.verify(RR,tPtr)) { default: TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId()); return ADD_REJECTED; @@ -154,7 +154,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential *)0; @@ -169,7 +169,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } - switch(tag.verify(RR)) { + switch(tag.verify(RR,tPtr)) { default: TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId()); return ADD_REJECTED; @@ -184,7 +184,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential *)0; @@ -199,7 +199,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } - switch(cap.verify(RR)) { + switch(cap.verify(RR,tPtr)) { default: TRACE("addCredential(Capability) for %s on %.16llx REJECTED (invalid)",cap.issuedTo().toString().c_str(),cap.networkId()); return ADD_REJECTED; @@ -214,9 +214,9 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev) { - switch(rev.verify(RR)) { + switch(rev.verify(RR,tPtr)) { default: return ADD_REJECTED; case 0: { @@ -239,7 +239,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential *)0; @@ -254,7 +254,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } - switch(coo.verify(RR)) { + switch(coo.verify(RR,tPtr)) { default: TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (invalid)",coo.issuedTo().toString().c_str(),coo.networkId()); return ADD_REJECTED; diff --git a/node/Membership.hpp b/node/Membership.hpp index 97510b57..c28d598c 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -158,13 +158,14 @@ public: * sends VERB_NETWORK_CREDENTIALS if the recipient might need them. * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param peerAddress Address of member peer (the one that this Membership describes) * @param nconf My network config * @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none * @param force If true, send objects regardless of last push time */ - void pushCredentials(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); + void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); /** * Check whether we should push MULTICAST_LIKEs to this peer @@ -226,27 +227,27 @@ public: /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev); /** * Validate and add a credential if signature is okay and it's otherwise good */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo); + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo); private: _RemoteCredential *_newTag(const uint64_t id); diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index f8d58501..8e534b5e 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -43,14 +43,14 @@ Multicaster::~Multicaster() { } -void Multicaster::addMultiple(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) +void Multicaster::addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) { const unsigned char *p = (const unsigned char *)addresses; const unsigned char *e = p + (5 * count); Mutex::Lock _l(_groups_m); MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; while (p != e) { - _add(now,nwid,mg,gs,Address(p,5)); + _add(tPtr,now,nwid,mg,gs,Address(p,5)); p += 5; } } @@ -152,6 +152,7 @@ std::vector

Multicaster::getMembers(uint64_t nwid,const MulticastGroup } void Multicaster::send( + void *tPtr, unsigned int limit, uint64_t now, uint64_t nwid, @@ -207,7 +208,7 @@ void Multicaster::send( for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { if (*ast != RR->identity.address()) { - out.sendOnly(RR,*ast); // optimization: don't use dedup log if it's a one-pass send + out.sendOnly(RR,tPtr,*ast); // optimization: don't use dedup log if it's a one-pass send if (++count >= limit) break; } @@ -217,7 +218,7 @@ void Multicaster::send( while ((count < limit)&&(idx < gs.members.size())) { Address ma(gs.members[indexes[idx++]].address); if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendOnly(RR,ma); // optimization: don't use dedup log if it's a one-pass send + out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send ++count; } } @@ -256,7 +257,7 @@ void Multicaster::send( if (com) com->serialize(outp); RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } @@ -280,7 +281,7 @@ void Multicaster::send( for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { if (*ast != RR->identity.address()) { - out.sendAndLog(RR,*ast); + out.sendAndLog(RR,tPtr,*ast); if (++count >= limit) break; } @@ -290,7 +291,7 @@ void Multicaster::send( while ((count < limit)&&(idx < gs.members.size())) { Address ma(gs.members[indexes[idx++]].address); if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) { - out.sendAndLog(RR,ma); + out.sendAndLog(RR,tPtr,ma); ++count; } } @@ -352,15 +353,15 @@ void Multicaster::clean(uint64_t now) } } -void Multicaster::addCredential(const CertificateOfMembership &com,bool alreadyValidated) +void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated) { - if ((alreadyValidated)||(com.verify(RR) == 0)) { + if ((alreadyValidated)||(com.verify(RR,tPtr) == 0)) { Mutex::Lock _l(_gatherAuth_m); _gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now(); } } -void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) +void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) { // assumes _groups_m is locked @@ -383,7 +384,7 @@ void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,Multi if (tx->atLimit()) gs.txQueue.erase(tx++); else { - tx->sendIfNew(RR,member); + tx->sendIfNew(RR,tPtr,member); if (tx->atLimit()) gs.txQueue.erase(tx++); else ++tx; diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 32dec9cf..f646a5be 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -90,10 +90,10 @@ public: * @param mg Multicast group * @param member New member address */ - inline void add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) + inline void add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) { Mutex::Lock _l(_groups_m); - _add(now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); + _add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); } /** @@ -101,6 +101,7 @@ public: * * It's up to the caller to check bounds on the array before calling this. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param nwid Network ID * @param mg Multicast group @@ -108,7 +109,7 @@ public: * @param count Number of addresses * @param totalKnown Total number of known addresses as reported by peer */ - void addMultiple(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); + void addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); /** * Remove a multicast group member (if present) @@ -150,6 +151,7 @@ public: /** * Send a multicast * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param limit Multicast limit * @param now Current time * @param nwid Network ID @@ -162,6 +164,7 @@ public: * @param len Length of packet data */ void send( + void *tPtr, unsigned int limit, uint64_t now, uint64_t nwid, @@ -191,7 +194,7 @@ public: * @param com Certificate of membership * @param alreadyValidated If true, COM has already been checked and found to be valid and signed */ - void addCredential(const CertificateOfMembership &com,bool alreadyValidated); + void addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated); /** * Check authorization for GATHER and LIKE for non-network-members @@ -209,7 +212,7 @@ public: } private: - void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); + void _add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); const RuntimeEnvironment *RR; diff --git a/node/Network.cpp b/node/Network.cpp index 38c1b0d9..0abfdf86 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -674,7 +674,7 @@ static _doZtFilterResult _doZtFilter( const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); -Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : +Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr) : RR(renv), _uPtr(uptr), _id(nwid), @@ -696,11 +696,11 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : Dictionary *dconf = new Dictionary(); NetworkConfig *nconf = new NetworkConfig(); try { - std::string conf(RR->node->dataStoreGet(confn)); + std::string conf(RR->node->dataStoreGet(tPtr,confn)); if (conf.length()) { dconf->load(conf.c_str()); if (nconf->fromDictionary(*dconf)) { - this->setConfiguration(*nconf,false); + this->setConfiguration(tPtr,*nconf,false); _lastConfigUpdate = 0; // we still want to re-request a new config from the network gotConf = true; } @@ -711,13 +711,13 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) : if (!gotConf) { // Save a one-byte CR to persist membership while we request a real netconf - RR->node->dataStorePut(confn,"\n",1,false); + RR->node->dataStorePut(tPtr,confn,"\n",1,false); } if (!_portInitialized) { ZT_VirtualNetworkConfig ctmp; _externalConfig(&ctmp); - _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); + _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); _portInitialized = true; } } @@ -729,15 +729,16 @@ Network::~Network() char n[128]; if (_destroyed) { - RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); + RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); - RR->node->dataStoreDelete(n); + RR->node->dataStoreDelete((void *)0,n); } else { - RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); + RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); } } bool Network::filterOutgoingPacket( + void *tPtr, const bool noTee, const Address &ztSource, const Address &ztDest, @@ -781,7 +782,7 @@ bool Network::filterOutgoingPacket( if ((!noTee)&&(cc2)) { Membership &m2 = _membership(cc2); - m2.pushCredentials(RR,now,cc2,_config,localCapabilityIndex,false); + m2.pushCredentials(RR,tPtr,now,cc2,_config,localCapabilityIndex,false); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -791,7 +792,7 @@ bool Network::filterOutgoingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength2); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } break; @@ -813,11 +814,11 @@ bool Network::filterOutgoingPacket( if (accept) { if (membership) - membership->pushCredentials(RR,now,ztDest,_config,localCapabilityIndex,false); + membership->pushCredentials(RR,tPtr,now,ztDest,_config,localCapabilityIndex,false); if ((!noTee)&&(cc)) { Membership &m2 = _membership(cc); - m2.pushCredentials(RR,now,cc,_config,localCapabilityIndex,false); + m2.pushCredentials(RR,tPtr,now,cc,_config,localCapabilityIndex,false); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -827,12 +828,12 @@ bool Network::filterOutgoingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } if ((ztDest != ztFinalDest)&&(ztFinalDest)) { Membership &m2 = _membership(ztFinalDest); - m2.pushCredentials(RR,now,ztFinalDest,_config,localCapabilityIndex,false); + m2.pushCredentials(RR,tPtr,now,ztFinalDest,_config,localCapabilityIndex,false); Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -842,7 +843,7 @@ bool Network::filterOutgoingPacket( outp.append((uint16_t)etherType); outp.append(frameData,frameLen); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); return false; // DROP locally, since we redirected } else { @@ -854,6 +855,7 @@ bool Network::filterOutgoingPacket( } int Network::filterIncomingPacket( + void *tPtr, const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, @@ -898,7 +900,7 @@ int Network::filterIncomingPacket( if (accept) { if (cc2) { - _membership(cc2).pushCredentials(RR,RR->node->now(),cc2,_config,-1,false); + _membership(cc2).pushCredentials(RR,tPtr,RR->node->now(),cc2,_config,-1,false); Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -908,7 +910,7 @@ int Network::filterIncomingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength2); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } break; } @@ -929,7 +931,7 @@ int Network::filterIncomingPacket( if (accept) { if (cc) { - _membership(cc).pushCredentials(RR,RR->node->now(),cc,_config,-1,false); + _membership(cc).pushCredentials(RR,tPtr,RR->node->now(),cc,_config,-1,false); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -939,11 +941,11 @@ int Network::filterIncomingPacket( outp.append((uint16_t)etherType); outp.append(frameData,ccLength); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - _membership(ztFinalDest).pushCredentials(RR,RR->node->now(),ztFinalDest,_config,-1,false); + _membership(ztFinalDest).pushCredentials(RR,tPtr,RR->node->now(),ztFinalDest,_config,-1,false); Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -953,7 +955,7 @@ int Network::filterIncomingPacket( outp.append((uint16_t)etherType); outp.append(frameData,frameLen); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); return 0; // DROP locally, since we redirected } @@ -972,12 +974,12 @@ bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBr return false; } -void Network::multicastSubscribe(const MulticastGroup &mg) +void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg) { Mutex::Lock _l(_lock); if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg); - _sendUpdatesToMembers(&mg); + _sendUpdatesToMembers(tPtr,&mg); } } @@ -989,7 +991,7 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) _myMulticastGroups.erase(i); } -uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) +uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) { const unsigned int start = ptr; @@ -1043,7 +1045,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc } // If it's not a duplicate, check chunk signature - const Identity controllerId(RR->topology->getIdentity(controller())); + const Identity controllerId(RR->topology->getIdentity(tPtr,controller())); if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? TRACE("unable to verify chunk from %s: don't have controller identity",source.toString().c_str()); return 0; @@ -1067,7 +1069,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc if ((*a != source)&&(*a != controller())) { Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG); outp.append(reinterpret_cast(chunk.data()) + start,chunk.size() - start); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } } @@ -1126,7 +1128,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc } if (nc) { - this->setConfiguration(*nc,true); + this->setConfiguration(tPtr,*nc,true); delete nc; return configUpdateId; } else { @@ -1136,7 +1138,7 @@ uint64_t Network::handleConfigChunk(const uint64_t packetId,const Address &sourc return 0; } -int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) +int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk) { // _lock is NOT locked when this is called try { @@ -1156,7 +1158,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) _portInitialized = true; _externalConfig(&ctmp); } - _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); + _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); if (saveToDisk) { Dictionary *d = new Dictionary(); @@ -1164,7 +1166,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) char n[64]; Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); if (nconf.toDictionary(*d,false)) - RR->node->dataStorePut(n,(const void *)d->data(),d->sizeBytes(),true); + RR->node->dataStorePut(tPtr,n,(const void *)d->data(),d->sizeBytes(),true); } catch ( ... ) {} delete d; } @@ -1176,7 +1178,7 @@ int Network::setConfiguration(const NetworkConfig &nconf,bool saveToDisk) return 0; } -void Network::requestConfiguration() +void Network::requestConfiguration(void *tPtr) { /* ZeroTier addresses can't begin with 0xff, so this is used to mark controllerless * network IDs. Controllerless network IDs only support unicast IPv6 using the 6plane @@ -1236,7 +1238,7 @@ void Network::requestConfiguration() nconf->type = ZT_NETWORK_TYPE_PUBLIC; Utils::snprintf(nconf->name,sizeof(nconf->name),"adhoc-%.04x-%.04x",(int)startPortRange,(int)endPortRange); - this->setConfiguration(*nconf,false); + this->setConfiguration(tPtr,*nconf,false); delete nconf; } else { this->setNotFound(); @@ -1284,10 +1286,10 @@ void Network::requestConfiguration() } outp.compress(); RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } -bool Network::gate(const SharedPtr &peer) +bool Network::gate(void *tPtr,const SharedPtr &peer) { const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -1298,8 +1300,8 @@ bool Network::gate(const SharedPtr &peer) if (!m) m = &(_membership(peer->address())); if (m->shouldLikeMulticasts(now)) { - m->pushCredentials(RR,now,peer->address(),_config,-1,false); - _announceMulticastGroupsTo(peer->address(),_allMulticastGroups()); + m->pushCredentials(RR,tPtr,now,peer->address(),_config,-1,false); + _announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups()); m->likingMulticasts(now); } return true; @@ -1377,31 +1379,31 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) } } -void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now) +void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now) { Mutex::Lock _l(_lock); const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); _multicastGroupsBehindMe.set(mg,now); if (tmp != _multicastGroupsBehindMe.size()) - _sendUpdatesToMembers(&mg); + _sendUpdatesToMembers(tPtr,&mg); } -Membership::AddCredentialResult Network::addCredential(const CertificateOfMembership &com) +Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com) { if (com.networkId() != _id) return Membership::ADD_REJECTED; const Address a(com.issuedTo()); Mutex::Lock _l(_lock); Membership &m = _membership(a); - const Membership::AddCredentialResult result = m.addCredential(RR,_config,com); + const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,com); if ((result == Membership::ADD_ACCEPTED_NEW)||(result == Membership::ADD_ACCEPTED_REDUNDANT)) { - m.pushCredentials(RR,RR->node->now(),a,_config,-1,false); - RR->mc->addCredential(com,true); + m.pushCredentials(RR,tPtr,RR->node->now(),a,_config,-1,false); + RR->mc->addCredential(tPtr,com,true); } return result; } -Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,const Revocation &rev) +Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev) { if (rev.networkId() != _id) return Membership::ADD_REJECTED; @@ -1409,7 +1411,7 @@ Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,c Mutex::Lock _l(_lock); Membership &m = _membership(rev.target()); - const Membership::AddCredentialResult result = m.addCredential(RR,_config,rev); + const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev); if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { Address *a = (Address *)0; @@ -1424,7 +1426,7 @@ Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,c outp.append((uint16_t)1); // one revocation! rev.serialize(outp); outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } } @@ -1495,7 +1497,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } } -void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup) +void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked const uint64_t now = RR->node->now(); @@ -1521,9 +1523,9 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou outp.append((uint16_t)0); // no tags outp.append((uint16_t)0); // no revocations outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } - _announceMulticastGroupsTo(*a,groups); + _announceMulticastGroupsTo(tPtr,*a,groups); } // Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it @@ -1537,9 +1539,9 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou outp.append((uint16_t)0); // no tags outp.append((uint16_t)0); // no revocations outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } - _announceMulticastGroupsTo(c,groups); + _announceMulticastGroupsTo(tPtr,c,groups); } } @@ -1556,17 +1558,17 @@ void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGrou Membership *m = (Membership *)0; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { - m->pushCredentials(RR,now,*a,_config,-1,false); + m->pushCredentials(RR,tPtr,now,*a,_config,-1,false); if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) { if (!newMulticastGroup) m->likingMulticasts(now); - _announceMulticastGroupsTo(*a,groups); + _announceMulticastGroupsTo(tPtr,*a,groups); } } } } -void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups) +void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups) { // Assumes _lock is locked Packet outp(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); @@ -1574,7 +1576,7 @@ void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); outp.reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); } @@ -1586,7 +1588,7 @@ void Network::_announceMulticastGroupsTo(const Address &peer,const std::vector ZT_PROTO_MIN_PACKET_LENGTH) { outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tPtr,outp,true); } } diff --git a/node/Network.hpp b/node/Network.hpp index 6cf6d974..fccc267a 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -77,10 +77,11 @@ public: * constructed to actually configure the port. * * @param renv Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param nwid Network ID * @param uptr Arbitrary pointer used by externally-facing API (for user use) */ - Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr); + Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr); ~Network(); @@ -101,6 +102,7 @@ public: * such as TEE may be taken, and credentials may be pushed, so this is not * side-effect-free. It's basically step one in sending something over VL2. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) * @param ztSource Source ZeroTier address * @param ztDest Destination ZeroTier address @@ -113,6 +115,7 @@ public: * @return True if packet should be sent, false if dropped or redirected */ bool filterOutgoingPacket( + void *tPtr, const bool noTee, const Address &ztSource, const Address &ztDest, @@ -131,6 +134,7 @@ public: * a match certain actions may be taken such as sending a copy of the packet * to a TEE or REDIRECT target. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param sourcePeer Source Peer * @param ztDest Destination ZeroTier address * @param macSource Ethernet layer source address @@ -142,6 +146,7 @@ public: * @return 0 == drop, 1 == accept, 2 == accept even if bridged */ int filterIncomingPacket( + void *tPtr, const SharedPtr &sourcePeer, const Address &ztDest, const MAC &macSource, @@ -163,9 +168,10 @@ public: /** * Subscribe to a multicast group * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param mg New multicast group */ - void multicastSubscribe(const MulticastGroup &mg); + void multicastSubscribe(void *tPtr,const MulticastGroup &mg); /** * Unsubscribe from a multicast group @@ -181,22 +187,24 @@ public: * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies * each chunk and once assembled applies the configuration. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param packetId Packet ID or 0 if none (e.g. via cluster path) * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) * @param chunk Buffer containing chunk * @param ptr Index of chunk and related fields in packet * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - uint64_t handleConfigChunk(const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); + uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); /** * Set network configuration * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param nconf Network configuration * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new */ - int setConfiguration(const NetworkConfig &nconf,bool saveToDisk); + int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk); /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this @@ -218,13 +226,18 @@ public: /** * Causes this network to request an updated configuration from its master node now + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - void requestConfiguration(); + void requestConfiguration(void *tPtr); /** * Determine whether this peer is permitted to communicate on this network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param peer Peer to check */ - bool gate(const SharedPtr &peer); + bool gate(void *tPtr,const SharedPtr &peer); /** * Do periodic cleanup and housekeeping tasks @@ -233,11 +246,13 @@ public: /** * Push state to members such as multicast group memberships and latest COM (if needed) + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - inline void sendUpdatesToMembers() + inline void sendUpdatesToMembers(void *tPtr) { Mutex::Lock _l(_lock); - _sendUpdatesToMembers((const MulticastGroup *)0); + _sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); } /** @@ -264,64 +279,66 @@ public: /** * Learn a multicast group that is bridged to our tap device * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param mg Multicast group * @param now Current time */ - void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now); + void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now); /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(const CertificateOfMembership &com); + Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com); /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(const Capability &cap) + inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) { if (cap.networkId() != _id) return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(cap.issuedTo()).addCredential(RR,_config,cap); + return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap); } /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(const Tag &tag) + inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) { if (tag.networkId() != _id) return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(tag.issuedTo()).addCredential(RR,_config,tag); + return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag); } /** * Validate a credential and learn it if it passes certificate and other checks */ - Membership::AddCredentialResult addCredential(const Address &sentFrom,const Revocation &rev); + Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(const CertificateOfOwnership &coo) + inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) { if (coo.networkId() != _id) return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _membership(coo.issuedTo()).addCredential(RR,_config,coo); + return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo); } /** * Force push credentials (COM, etc.) to a peer now * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param to Destination peer address * @param now Current time */ - inline void pushCredentialsNow(const Address &to,const uint64_t now) + inline void pushCredentialsNow(void *tPtr,const Address &to,const uint64_t now) { Mutex::Lock _l(_lock); - _membership(to).pushCredentials(RR,now,to,_config,-1,true); + _membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true); } /** @@ -353,8 +370,8 @@ private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked bool _gate(const SharedPtr &peer); - void _sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup); - void _announceMulticastGroupsTo(const Address &peer,const std::vector &allMulticastGroups); + void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); + void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; Membership &_membership(const Address &a); diff --git a/node/Node.cpp b/node/Node.cpp index 1125ca7a..4e8d6655 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,7 +46,7 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : +Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : _RR(this), RR(&_RR), _uPtr(uptr), @@ -72,26 +72,26 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : memset(_prngStream,0,sizeof(_prngStream)); _prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream)); - std::string idtmp(dataStoreGet("identity.secret")); + std::string idtmp(dataStoreGet(tptr,"identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { TRACE("identity.secret not found, generating..."); RR->identity.generate(); idtmp = RR->identity.toString(true); - if (!dataStorePut("identity.secret",idtmp,true)) + if (!dataStorePut(tptr,"identity.secret",idtmp,true)) throw std::runtime_error("unable to write identity.secret"); } RR->publicIdentityStr = RR->identity.toString(false); RR->secretIdentityStr = RR->identity.toString(true); - idtmp = dataStoreGet("identity.public"); + idtmp = dataStoreGet(tptr,"identity.public"); if (idtmp != RR->publicIdentityStr) { - if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) + if (!dataStorePut(tptr,"identity.public",RR->publicIdentityStr,false)) throw std::runtime_error("unable to write identity.public"); } try { RR->sw = new Switch(RR); RR->mc = new Multicaster(RR); - RR->topology = new Topology(RR); + RR->topology = new Topology(RR,tptr); RR->sa = new SelfAwareness(RR); } catch ( ... ) { delete RR->sa; @@ -101,7 +101,7 @@ Node::Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : throw; } - postEvent(ZT_EVENT_UP); + postEvent(tptr,ZT_EVENT_UP); } Node::~Node() @@ -121,6 +121,7 @@ Node::~Node() } ZT_ResultCode Node::processWirePacket( + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -129,11 +130,12 @@ ZT_ResultCode Node::processWirePacket( volatile uint64_t *nextBackgroundTaskDeadline) { _now = now; - RR->sw->onRemotePacket(*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); + RR->sw->onRemotePacket(tptr,*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); return ZT_RESULT_OK; } ZT_ResultCode Node::processVirtualNetworkFrame( + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -147,7 +149,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( _now = now; SharedPtr nw(this->network(nwid)); if (nw) { - RR->sw->onLocalEthernet(nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); + RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); return ZT_RESULT_OK; } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } @@ -156,9 +158,10 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : lastReceiveFromUpstream(0), RR(renv), + _tPtr(tPtr), _upstreamsToContact(upstreamsToContact), _now(now), _bestCurrentUpstream(RR->topology->getUpstreamPeer()) @@ -176,21 +179,21 @@ public: // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow // them to perform three way handshake introductions for both stacks. - if (!p->doPingAndKeepalive(_now,AF_INET)) { + if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); contacted = true; break; } } } else contacted = true; - if (!p->doPingAndKeepalive(_now,AF_INET6)) { + if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET6)) { for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); contacted = true; break; } @@ -200,24 +203,25 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); + p->sendHELLO(_tPtr,up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); _upstreamsToContact.erase(p->address()); // erase from upstreams to contact so that we can WHOIS those that remain } else if (p->isActive(_now)) { - p->doPingAndKeepalive(_now,-1); + p->doPingAndKeepalive(_tPtr,_now,-1); } } private: const RuntimeEnvironment *RR; + void *_tPtr; Hashtable< Address,std::vector > &_upstreamsToContact; const uint64_t _now; const SharedPtr _bestCurrentUpstream; }; -ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) { _now = now; Mutex::Lock bl(_backgroundTasksLock); @@ -235,16 +239,16 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) needConfig.push_back(n->second); - n->second->sendUpdatesToMembers(); + n->second->sendUpdatesToMembers(tptr); } } for(std::vector< SharedPtr >::const_iterator n(needConfig.begin());n!=needConfig.end();++n) - (*n)->requestConfiguration(); + (*n)->requestConfiguration(tptr); // Do pings and keepalives Hashtable< Address,std::vector > upstreamsToContact; RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,upstreamsToContact,now); + _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) @@ -252,13 +256,13 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB Address *upstreamAddress = (Address *)0; std::vector *upstreamStableEndpoints = (std::vector *)0; while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(*upstreamAddress); + RR->sw->requestWhois(tptr,*upstreamAddress); // Update online status, post status change as event const bool oldOnline = _online; _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); if (oldOnline != _online) - postEvent(_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); + postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -286,7 +290,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate } else { #endif - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); + *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); #ifdef ZT_ENABLE_CLUSTER } #endif @@ -297,17 +301,17 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB return ZT_RESULT_OK; } -ZT_ResultCode Node::join(uint64_t nwid,void *uptr) +ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr) { Mutex::Lock _l(_networks_m); SharedPtr nw = _network(nwid); if(!nw) - _networks.push_back(std::pair< uint64_t,SharedPtr >(nwid,SharedPtr(new Network(RR,nwid,uptr)))); + _networks.push_back(std::pair< uint64_t,SharedPtr >(nwid,SharedPtr(new Network(RR,tptr,nwid,uptr)))); std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<> return ZT_RESULT_OK; } -ZT_ResultCode Node::leave(uint64_t nwid,void **uptr) +ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr) { std::vector< std::pair< uint64_t,SharedPtr > > newn; Mutex::Lock _l(_networks_m); @@ -324,11 +328,11 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr) return ZT_RESULT_OK; } -ZT_ResultCode Node::multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +ZT_ResultCode Node::multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) { SharedPtr nw(this->network(nwid)); if (nw) { - nw->multicastSubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); + nw->multicastSubscribe(tptr,MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); return ZT_RESULT_OK; } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } @@ -342,15 +346,15 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } -ZT_ResultCode Node::orbit(uint64_t moonWorldId,uint64_t moonSeed) +ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed) { - RR->topology->addMoon(moonWorldId,Address(moonSeed)); + RR->topology->addMoon(tptr,moonWorldId,Address(moonSeed)); return ZT_RESULT_OK; } -ZT_ResultCode Node::deorbit(uint64_t moonWorldId) +ZT_ResultCode Node::deorbit(void *tptr,uint64_t moonWorldId) { - RR->topology->removeMoon(moonWorldId); + RR->topology->removeMoon(tptr,moonWorldId); return ZT_RESULT_OK; } @@ -465,7 +469,7 @@ void Node::clearLocalInterfaceAddresses() _directPaths.clear(); } -int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) { try { if (RR->identity.address().toInt() != dest) { @@ -473,7 +477,7 @@ int Node::sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigne outp.append(typeId); outp.append(data,len); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send(tptr,outp,true); return 1; } } catch ( ... ) {} @@ -486,7 +490,7 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController->init(RR->identity,this); } -ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { if (test->hopCount > 0) { try { @@ -516,7 +520,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[0].breadth;++a) { outp.newInitializationVector(); outp.setDestination(Address(test->hops[0].addresses[a])); - RR->sw->send(outp,true); + RR->sw->send(tptr,outp,true); } } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet @@ -616,13 +620,13 @@ void Node::clusterStatus(ZT_ClusterStatus *cs) /* Node methods used only within node/ */ /****************************************************************************/ -std::string Node::dataStoreGet(const char *name) +std::string Node::dataStoreGet(void *tPtr,const char *name) { char buf[1024]; std::string r; unsigned long olen = 0; do { - long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); + long n = _cb.dataStoreGetFunction(reinterpret_cast(this),_uPtr,tPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen); if (n <= 0) return std::string(); r.append(buf,n); @@ -630,7 +634,7 @@ std::string Node::dataStoreGet(const char *name) return r; } -bool Node::shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) { if (!Path::isAddressValidForPath(remoteAddress)) return false; @@ -650,7 +654,7 @@ bool Node::shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddre } } - return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); + return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); } #ifdef ZT_TRACE @@ -728,7 +732,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de if (destination == RR->identity.address()) { SharedPtr n(network(nwid)); if (!n) return; - n->setConfiguration(nc,true); + n->setConfiguration((void *)0,nc,true); } else { Dictionary *dconf = new Dictionary(); try { @@ -762,7 +766,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); outp.compress(); - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); chunkIndex += chunkLen; } } @@ -779,7 +783,7 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev) if (destination == RR->identity.address()) { SharedPtr n(network(rev.networkId())); if (!n) return; - n->addCredential(RR->identity.address(),rev); + n->addCredential((void *)0,RR->identity.address(),rev); } else { Packet outp(destination,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); outp.append((uint8_t)0x00); @@ -788,7 +792,7 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev) outp.append((uint16_t)1); rev.serialize(outp); outp.append((uint16_t)0); - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); } } @@ -823,7 +827,7 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des break; } outp.append(nwid); - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); } // else we can't send an ERROR() in response to nothing, so discard } @@ -835,11 +839,11 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) { *node = (ZT_Node *)0; try { - *node = reinterpret_cast(new ZeroTier::Node(uptr,callbacks,now)); + *node = reinterpret_cast(new ZeroTier::Node(uptr,tptr,callbacks,now)); return ZT_RESULT_OK; } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; @@ -859,6 +863,7 @@ void ZT_Node_delete(ZT_Node *node) enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -867,7 +872,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processWirePacket(now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processWirePacket(tptr,now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -877,6 +882,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -888,7 +894,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processVirtualNetworkFrame(now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -896,10 +902,10 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( } } -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processBackgroundTasks(now,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -907,10 +913,10 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol } } -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr) +enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr) { try { - return reinterpret_cast(node)->join(nwid,uptr); + return reinterpret_cast(node)->join(nwid,uptr,tptr); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -918,10 +924,10 @@ enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr) } } -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr) +enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr) { try { - return reinterpret_cast(node)->leave(nwid,uptr); + return reinterpret_cast(node)->leave(nwid,uptr,tptr); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -929,10 +935,10 @@ enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr) } } -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) { try { - return reinterpret_cast(node)->multicastSubscribe(nwid,multicastGroup,multicastAdi); + return reinterpret_cast(node)->multicastSubscribe(tptr,nwid,multicastGroup,multicastAdi); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { @@ -951,19 +957,19 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint } } -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,uint64_t moonWorldId,uint64_t moonSeed) +enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed) { try { - return reinterpret_cast(node)->orbit(moonWorldId,moonSeed); + return reinterpret_cast(node)->orbit(tptr,moonWorldId,moonSeed); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } } -ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,uint64_t moonWorldId) +ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) { try { - return reinterpret_cast(node)->deorbit(moonWorldId); + return reinterpret_cast(node)->deorbit(tptr,moonWorldId); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -1031,10 +1037,10 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) } catch ( ... ) {} } -int ZT_Node_sendUserMessage(ZT_Node *node,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) { try { - return reinterpret_cast(node)->sendUserMessage(dest,typeId,data,len); + return reinterpret_cast(node)->sendUserMessage(tptr,dest,typeId,data,len); } catch ( ... ) { return 0; } @@ -1047,10 +1053,10 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } -enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { try { - return reinterpret_cast(node)->circuitTestBegin(test,reportCallback); + return reinterpret_cast(node)->circuitTestBegin(tptr,test,reportCallback); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } diff --git a/node/Node.hpp b/node/Node.hpp index 21eac617..03bd7a8c 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -65,7 +65,7 @@ class World; class Node : public NetworkController::Sender { public: - Node(void *uptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); + Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); virtual ~Node(); // Get rid of alignment warnings on 32-bit Windows and possibly improve performance @@ -77,6 +77,7 @@ public: // Public API Functions ---------------------------------------------------- ZT_ResultCode processWirePacket( + void *tptr, uint64_t now, const struct sockaddr_storage *localAddress, const struct sockaddr_storage *remoteAddress, @@ -84,6 +85,7 @@ public: unsigned int packetLength, volatile uint64_t *nextBackgroundTaskDeadline); ZT_ResultCode processVirtualNetworkFrame( + void *tptr, uint64_t now, uint64_t nwid, uint64_t sourceMac, @@ -93,13 +95,13 @@ public: const void *frameData, unsigned int frameLength, volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode join(uint64_t nwid,void *uptr); - ZT_ResultCode leave(uint64_t nwid,void **uptr); - ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); + ZT_ResultCode processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); + ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); + ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); + ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode orbit(uint64_t moonWorldId,uint64_t moonSeed); - ZT_ResultCode deorbit(uint64_t moonWorldId); + ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed); + ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId); uint64_t address() const; void status(ZT_NodeStatus *status) const; ZT_PeerList *peers() const; @@ -108,9 +110,9 @@ public: void freeQueryResult(void *qr); int addLocalInterfaceAddress(const struct sockaddr_storage *addr); void clearLocalInterfaceAddresses(); - int sendUserMessage(uint64_t dest,uint64_t typeId,const void *data,unsigned int len); + int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); void setNetconfMaster(void *networkControllerInstance); - ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); + ZT_ResultCode circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); void circuitTestEnd(ZT_CircuitTest *test); ZT_ResultCode clusterInit( unsigned int myId, @@ -132,11 +134,12 @@ public: inline uint64_t now() const throw() { return _now; } - inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) + inline bool putPacket(void *tPtr,const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { return (_cb.wirePacketSendFunction( reinterpret_cast(this), _uPtr, + tPtr, reinterpret_cast(&localAddress), reinterpret_cast(&addr), data, @@ -144,11 +147,12 @@ public: ttl) == 0); } - inline void putFrame(uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) + inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { _cb.virtualNetworkFrameFunction( reinterpret_cast(this), _uPtr, + tPtr, nwid, nuptr, source.toInt(), @@ -191,14 +195,14 @@ public: return _directPaths; } - inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } - inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } - inline void dataStoreDelete(const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } - std::string dataStoreGet(const char *name); + inline bool dataStorePut(void *tPtr,const char *name,const void *data,unsigned int len,bool secure) { return (_cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,tPtr,name,data,len,(int)secure) == 0); } + inline bool dataStorePut(void *tPtr,const char *name,const std::string &data,bool secure) { return dataStorePut(tPtr,name,(const void *)data.data(),(unsigned int)data.length(),secure); } + inline void dataStoreDelete(void *tPtr,const char *name) { _cb.dataStorePutFunction(reinterpret_cast(this),_uPtr,tPtr,name,(const void *)0,0,0); } + std::string dataStoreGet(void *tPtr,const char *name); - inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,ev,md); } + inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,tPtr,ev,md); } - inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,nwid,nuptr,op,nc); } + inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,tPtr,nwid,nuptr,op,nc); } inline bool online() const throw() { return _online; } @@ -206,8 +210,8 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif - bool shouldUsePathForZeroTierTraffic(const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); - inline bool externalPathLookup(const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } + bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); + inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); void postCircuitTestReport(const ZT_CircuitTestReport *report); diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index d4cb87cb..285bfa5d 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -85,18 +85,18 @@ void OutboundMulticast::init( memcpy(_frameData,payload,_frameLen); } -void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toAddr) +void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) { const SharedPtr nw(RR->node->network(_nwid)); const Address toAddr2(toAddr); - if ((nw)&&(nw->filterOutgoingPacket(true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { + if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr2); RR->node->expectReplyTo(_packet.packetId()); Packet tmp(_packet); // make a copy of packet so as not to garble the original -- GitHub issue #461 - RR->sw->send(tmp,true); + RR->sw->send(tPtr,tmp,true); } } diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 6370d0d7..0ecf113f 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -99,33 +99,36 @@ public: * Just send without checking log * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param toAddr Destination address */ - void sendOnly(const RuntimeEnvironment *RR,const Address &toAddr); + void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr); /** * Just send and log but do not check sent log * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param toAddr Destination address */ - inline void sendAndLog(const RuntimeEnvironment *RR,const Address &toAddr) + inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) { _alreadySentTo.push_back(toAddr); - sendOnly(RR,toAddr); + sendOnly(RR,tPtr,toAddr); } /** * Try to send this to a given peer if it hasn't been sent to them already * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param toAddr Destination address * @return True if address is new and packet was sent to switch, false if duplicate */ - inline bool sendIfNew(const RuntimeEnvironment *RR,const Address &toAddr) + inline bool sendIfNew(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) { if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) { - sendAndLog(RR,toAddr); + sendAndLog(RR,tPtr,toAddr); return true; } else { return false; diff --git a/node/Path.cpp b/node/Path.cpp index 5592bacc..7366b56f 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -22,9 +22,9 @@ namespace ZeroTier { -bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) +bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) { - if (RR->node->putPacket(_localAddress,address(),data,len)) { + if (RR->node->putPacket(tPtr,_localAddress,address(),data,len)) { _lastOut = now; return true; } diff --git a/node/Path.hpp b/node/Path.hpp index 62f29c22..aef628d4 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -186,12 +186,13 @@ public: * Send a packet via this path (last out time is also updated) * * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param data Packet data * @param len Packet length * @param now Current time * @return True if transport reported success */ - bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now); + bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now); /** * Manually update last sent time diff --git a/node/Peer.cpp b/node/Peer.cpp index fa3ce6c8..0cc23e33 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -68,6 +68,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident } void Peer::received( + void *tPtr, const SharedPtr &path, const unsigned int hops, const uint64_t packetId, @@ -161,7 +162,7 @@ void Peer::received( } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); @@ -206,7 +207,7 @@ void Peer::received( #endif } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); + attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } } @@ -281,7 +282,7 @@ void Peer::received( if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,outp.data(),outp.size(),now); + path->send(RR,tPtr,outp.data(),outp.size(),now); } } } @@ -299,7 +300,7 @@ bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const return false; } -bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) { Mutex::Lock _l(_paths_m); @@ -316,7 +317,7 @@ bool Peer::sendDirect(const void *data,unsigned int len,uint64_t now,bool forceE } if (bestp >= 0) { - return _paths[bestp].path->send(RR,data,len,now); + return _paths[bestp].path->send(RR,tPtr,data,len,now); } else { return false; } @@ -345,7 +346,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) } } -void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -387,35 +388,35 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u if (atAddress) { outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); } else { - RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC + RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true,counter); - RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); } else { - sendHELLO(localAddr,atAddress,now,counter); + sendHELLO(tPtr,localAddr,atAddress,now,counter); } } -void Peer::tryMemorizedPath(uint64_t now) +void Peer::tryMemorizedPath(void *tPtr,uint64_t now) { if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { _lastTriedMemorizedPath = now; InetAddress mp; - if (RR->node->externalPathLookup(_id.address(),-1,mp)) - attemptToContactAt(InetAddress(),mp,now,true,0); + if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) + attemptToContactAt(tPtr,InetAddress(),mp,now,true,0); } } -bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) +bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); @@ -433,7 +434,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) if (bestp >= 0) { if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); _paths[bestp].path->sent(now); } return true; @@ -452,12 +453,12 @@ bool Peer::hasActiveDirectPath(uint64_t now) const return false; } -void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) +void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) { Mutex::Lock _l(_paths_m); for(unsigned int p=0;p<_numPaths;++p) { if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); _paths[p].path->sent(now); _paths[p].lastReceive = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index 72040b1d..41836410 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -84,6 +84,7 @@ public: * This is called by the decode pipe when a packet is proven to be authentic * and appears to be valid. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param path Path over which packet was received * @param hops ZeroTier (not IP) hops * @param packetId Packet ID @@ -93,6 +94,7 @@ public: * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established */ void received( + void *tPtr, const SharedPtr &path, const unsigned int hops, const uint64_t packetId, @@ -125,13 +127,14 @@ public: /** * Send via best direct path * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param data Packet data * @param len Packet length * @param now Current time * @param forceEvenIfDead If true, send even if the path is not 'alive' * @return True if we actually sent something */ - bool sendDirect(const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); /** * Get the best current direct path @@ -147,41 +150,47 @@ public: * * No statistics or sent times are updated here. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localAddr Local address * @param atAddress Destination address * @param now Current time * @param counter Outgoing packet counter */ - void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address * * No statistics or sent times are updated here. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localAddr Local address * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param counter Outgoing packet counter */ - void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known * * Under the hood this is done periodically based on ZT_TRY_MEMORIZED_PATH_INTERVAL. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time */ - void tryMemorizedPath(uint64_t now); + void tryMemorizedPath(void *tPtr,uint64_t now); /** * Send pings or keepalives depending on configured timeouts * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param inetAddressFamily Keep this address family alive, or -1 for any * @return True if we have at least one direct path of the given family (or any if family is -1) */ - bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); + bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); /** * @param now Current time @@ -195,11 +204,12 @@ public: * Resetting a path involves sending an ECHO to it and then deactivating * it until or unless it responds. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param scope IP scope * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - void resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); /** * Get most recently active path addresses for IPv4 and/or IPv6 diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 420476a4..bab5653c 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -25,13 +25,13 @@ namespace ZeroTier { -int Revocation::verify(const RuntimeEnvironment *RR) const +int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } try { diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 93c55112..8b9ce6dd 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -113,9 +113,10 @@ public: * Verify this revocation's signature * * @param RR Runtime environment to provide for peer lookup, etc. + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template inline void serialize(Buffer &b,const bool forSign = false) const diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index e84b7b65..cba84cdc 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -40,15 +40,17 @@ namespace ZeroTier { class _ResetWithinScope { public: - _ResetWithinScope(uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : + _ResetWithinScope(void *tPtr,uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : _now(now), + _tPtr(tPtr), _family(inetAddressFamily), _scope(scope) {} - inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_scope,_family,_now); } + inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); } private: uint64_t _now; + void *_tPtr; int _family; InetAddress::IpScope _scope; }; @@ -59,7 +61,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) +void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -91,7 +93,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLoc } // Reset all paths within this scope and address family - _ResetWithinScope rset(now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); + _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); } else { // Otherwise just update DB to use to determine external surface info diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4bdafeb2..c1db0c84 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -47,7 +47,7 @@ public: * @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param now Current time */ - void iam(const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); + void iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); /** * Clean up database periodically diff --git a/node/Switch.cpp b/node/Switch.cpp index aab2e7ff..62674472 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -64,7 +64,7 @@ Switch::Switch(const RuntimeEnvironment *renv) : { } -void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) +void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) { try { const uint64_t now = RR->node->now(); @@ -81,15 +81,15 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from const Address beaconAddr(reinterpret_cast(data) + 8,5); if (beaconAddr == RR->identity.address()) return; - if (!RR->node->shouldUsePathForZeroTierTraffic(beaconAddr,localAddr,fromAddr)) + if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localAddr,fromAddr)) return; - const SharedPtr peer(RR->topology->getPeer(beaconAddr)); + const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr)); if (peer) { // we'll only respond to beacons from known peers if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses _lastBeaconResponse = now; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); outp.armor(peer->key(),true,path->nextOutgoingCounter()); - path->send(RR,outp.data(),outp.size(),now); + path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -115,8 +115,8 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. // It wouldn't hurt anything, just redundant and unnecessary. - SharedPtr relayTo = RR->topology->getPeer(destination); - if ((!relayTo)||(!relayTo->sendDirect(fragment.data(),fragment.size(),now,false))) { + SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); + if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { #ifdef ZT_ENABLE_CLUSTER if ((RR->cluster)&&(!isClusterFrontplane)) { RR->cluster->relayViaCluster(Address(),destination,fragment.data(),fragment.size(),false); @@ -127,7 +127,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from // Don't know peer or no direct path -- so relay via someone upstream relayTo = RR->topology->getUpstreamPeer(); if (relayTo) - relayTo->sendDirect(fragment.data(),fragment.size(),now,true); + relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); } } else { TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); @@ -171,7 +171,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - if (rq->frag0.tryDecode(RR)) { + if (rq->frag0.tryDecode(RR,tPtr)) { rq->timestamp = 0; // packet decoded, free entry } else { rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something @@ -212,8 +212,8 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from packet.incrementHops(); #endif - SharedPtr relayTo = RR->topology->getPeer(destination); - if ((relayTo)&&(relayTo->sendDirect(packet.data(),packet.size(),now,false))) { + SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); + if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { // don't send RENDEZVOUS for cluster frontplane relays const InetAddress *hintToSource = (InetAddress *)0; const InetAddress *hintToDest = (InetAddress *)0; @@ -222,7 +222,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from InetAddress sourceV4,sourceV6; relayTo->getRendezvousAddresses(now,destV4,destV6); - const SharedPtr sourcePeer(RR->topology->getPeer(source)); + const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); if (sourcePeer) { sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6); if ((destV6)&&(sourceV6)) { @@ -249,7 +249,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from outp.append((uint8_t)4); outp.append(hintToSource->rawIpData(),4); } - send(outp,true); + send(tPtr,outp,true); } else { Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS); outp.append((uint8_t)0); @@ -262,7 +262,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from outp.append((uint8_t)4); outp.append(hintToDest->rawIpData(),4); } - send(outp,true); + send(tPtr,outp,true); } ++alt; } @@ -278,7 +278,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from #endif relayTo = RR->topology->getUpstreamPeer(&source,1,true); if (relayTo) - relayTo->sendDirect(packet.data(),packet.size(),now,true); + relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } } else { TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); @@ -321,7 +321,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from for(unsigned int f=1;ftotalFragments;++f) rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - if (rq->frag0.tryDecode(RR)) { + if (rq->frag0.tryDecode(RR,tPtr)) { rq->timestamp = 0; // packet decoded, free entry } else { rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something @@ -334,7 +334,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } else { // Packet is unfragmented, so just process it IncomingPacket packet(data,len,path,now); - if (!packet.tryDecode(RR)) { + if (!packet.tryDecode(RR,tPtr)) { Mutex::Lock _l(_rxQueue_m); RXQueueEntry *rq = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]); unsigned long i = ZT_RX_QUEUE_SIZE - 1; @@ -362,7 +362,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from } } -void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { if (!network->hasConfig()) return; @@ -474,7 +474,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c adv[42] = (checksum >> 8) & 0xff; adv[43] = checksum & 0xff; - RR->node->putFrame(network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); + RR->node->putFrame(tPtr,network->id(),network->userPtr(),peerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query. } // else no NDP emulation } // else no NDP emulation @@ -491,17 +491,18 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c * multicast addresses on bridge interfaces and subscribing each slave. * But in that case this does no harm, as the sets are just merged. */ if (fromBridged) - network->learnBridgedMulticastGroup(multicastGroup,RR->node->now()); + network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now()); //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. - if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } RR->mc->send( + tPtr, network->config().multicastLimit, RR->node->now(), network->id(), @@ -514,14 +515,14 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c len); } else if (to == network->mac()) { // Destination is this node, so just reinject it - RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,vlanId,data,len); + RR->node->putFrame(tPtr,network->id(),network->userPtr(),from,to,etherType,vlanId,data,len); } else if (to[0] == MAC::firstOctetForNetwork(network->id())) { // Destination is another ZeroTier peer on the same network Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this - SharedPtr toPeer(RR->topology->getPeer(toZT)); + SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); - if (!network->filterOutgoingPacket(false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } @@ -536,7 +537,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append(data,len); if (!network->config().disableCompression()) outp.compress(); - send(outp,true); + send(tPtr,outp,true); } else { Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); @@ -544,7 +545,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append(data,len); if (!network->config().disableCompression()) outp.compress(); - send(outp,true); + send(tPtr,outp,true); } //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); @@ -554,7 +555,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c // We filter with a NULL destination ZeroTier address first. Filtrations // for each ZT destination are also done below. This is the same rationale // and design as for multicast. - if (!network->filterOutgoingPacket(false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); return; } @@ -592,7 +593,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } for(unsigned int b=0;bfilterOutgoingPacket(true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId)) { + if (network->filterOutgoingPacket(tPtr,true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId)) { Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); outp.append((uint8_t)0x00); @@ -602,7 +603,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.append(data,len); if (!network->config().disableCompression()) outp.compress(); - send(outp,true); + send(tPtr,outp,true); } else { TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); } @@ -610,20 +611,20 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } } -void Switch::send(Packet &packet,bool encrypt) +void Switch::send(void *tPtr,Packet &packet,bool encrypt) { if (packet.destination() == RR->identity.address()) { TRACE("BUG: caught attempt to send() to self, ignored"); return; } - if (!_trySend(packet,encrypt)) { + if (!_trySend(tPtr,packet,encrypt)) { Mutex::Lock _l(_txQueue_m); _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); } } -void Switch::requestWhois(const Address &addr) +void Switch::requestWhois(void *tPtr,const Address &addr) { #ifdef ZT_TRACE if (addr == RR->identity.address()) { @@ -644,10 +645,10 @@ void Switch::requestWhois(const Address &addr) } } if (inserted) - _sendWhoisRequest(addr,(const Address *)0,0); + _sendWhoisRequest(tPtr,addr,(const Address *)0,0); } -void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) +void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) { { // cancel pending WHOIS since we now know this peer Mutex::Lock _l(_outstandingWhoisRequests_m); @@ -660,7 +661,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) while (i) { RXQueueEntry *rq = &(_rxQueue[--i]); if ((rq->timestamp)&&(rq->complete)) { - if (rq->frag0.tryDecode(RR)) + if (rq->frag0.tryDecode(RR,tPtr)) rq->timestamp = 0; } } @@ -670,7 +671,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else ++txi; } else ++txi; @@ -678,7 +679,7 @@ void Switch::doAnythingWaitingForPeer(const SharedPtr &peer) } } -unsigned long Switch::doTimerTasks(uint64_t now) +unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) { unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum @@ -695,7 +696,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) _outstandingWhoisRequests.erase(*a); } else { r->lastSent = now; - r->peersConsulted[r->retries] = _sendWhoisRequest(*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); + r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); TRACE("WHOIS %s (retry %u)",a->toString().c_str(),r->retries); ++r->retries; nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); @@ -709,7 +710,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); @@ -743,19 +744,19 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address return false; } -Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) +Address Switch::_sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { SharedPtr upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); if (upstream) { Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); RR->node->expectReplyTo(outp.packetId()); - send(outp,true); + send(tPtr,outp,true); } return Address(); } -bool Switch::_trySend(Packet &packet,bool encrypt) +bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; const uint64_t now = RR->node->now(); @@ -769,7 +770,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) clusterMostRecentMemberId = RR->cluster->checkSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); #endif - const SharedPtr peer(RR->topology->getPeer(destination)); + const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); if (peer) { /* First get the best path, and if it's dead (and this is not a root) * we attempt to re-activate that path but this packet will flow @@ -784,7 +785,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { #endif if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); + peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } #ifdef ZT_ENABLE_CLUSTER @@ -801,7 +802,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #else if (!viaPath) { #endif - peer->tryMemorizedPath(now); // periodically attempt memorized or statically defined paths, if any are known + peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known const SharedPtr relay(RR->topology->getUpstreamPeer()); if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { if (!(viaPath = peer->getBestPath(now,true))) @@ -816,7 +817,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #ifdef ZT_ENABLE_CLUSTER if (clusterMostRecentMemberId < 0) { #else - requestWhois(destination); + requestWhois(tPtr,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly #endif #ifdef ZT_ENABLE_CLUSTER @@ -844,9 +845,9 @@ bool Switch::_trySend(Packet &packet,bool encrypt) #endif #ifdef ZT_ENABLE_CLUSTER - if ( ((viaPath)&&(viaPath->send(RR,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { + if ( ((viaPath)&&(viaPath->send(RR,tPtr,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { #else - if (viaPath->send(RR,packet.data(),chunkSize,now)) { + if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { #endif if (chunkSize < packet.size()) { // Too big for one packet, fragment the rest @@ -866,7 +867,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt) else if (clusterMostRecentMemberId >= 0) RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,frag.data(),frag.size()); #else - viaPath->send(RR,frag.data(),frag.size(),now); + viaPath->send(RR,tPtr,frag.data(),frag.size(),now); #endif fragStart += chunkSize; remaining -= chunkSize; diff --git a/node/Switch.hpp b/node/Switch.hpp index 9245c036..ff350934 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -59,16 +59,18 @@ public: /** * Called when a packet is received from the real network * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localAddr Local interface address * @param fromAddr Internet IP address of origin * @param data Packet data * @param len Packet length */ - void onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); + void onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); /** * Called when a packet comes from a local Ethernet tap * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param network Which network's TAP did this packet come from? * @param from Originating MAC address * @param to Destination MAC address @@ -77,7 +79,7 @@ public: * @param data Ethernet payload * @param len Frame length */ - void onLocalEthernet(const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); + void onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); /** * Send a packet to a ZeroTier address (destination in packet) @@ -91,26 +93,29 @@ public: * Needless to say, the packet's source must be this node. Otherwise it * won't be encrypted right. (This is not used for relaying.) * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param packet Packet to send (buffer may be modified) * @param encrypt Encrypt packet payload? (always true except for HELLO) */ - void send(Packet &packet,bool encrypt); + void send(void *tPtr,Packet &packet,bool encrypt); /** * Request WHOIS on a given address * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param addr Address to look up */ - void requestWhois(const Address &addr); + void requestWhois(void *tPtr,const Address &addr); /** * Run any processes that are waiting for this peer's identity * * Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param peer New peer */ - void doAnythingWaitingForPeer(const SharedPtr &peer); + void doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer); /** * Perform retries and other periodic timer tasks @@ -118,15 +123,16 @@ public: * This can return a very long delay if there are no pending timer * tasks. The caller should cap this comparatively vs. other values. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @return Number of milliseconds until doTimerTasks() should be run again */ - unsigned long doTimerTasks(uint64_t now); + unsigned long doTimerTasks(void *tPtr,uint64_t now); private: bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); - Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); - bool _trySend(Packet &packet,bool encrypt); // packet is modified if return is true + Address _sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); + bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; diff --git a/node/Tag.cpp b/node/Tag.cpp index eb4026bc..3f924da1 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -25,13 +25,13 @@ namespace ZeroTier { -int Tag::verify(const RuntimeEnvironment *RR) const +int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const { if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) return -1; - const Identity id(RR->topology->getIdentity(_signedBy)); + const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(_signedBy); + RR->sw->requestWhois(tPtr,_signedBy); return 1; } try { diff --git a/node/Tag.hpp b/node/Tag.hpp index 146e8da9..38085906 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -105,9 +105,10 @@ public: * Check this tag's signature * * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag */ - int verify(const RuntimeEnvironment *RR) const; + int verify(const RuntimeEnvironment *RR,void *tPtr) const; template inline void serialize(Buffer &b,const bool forSign = false) const diff --git a/node/Topology.cpp b/node/Topology.cpp index 21547cd2..a1d37332 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -55,19 +55,19 @@ namespace ZeroTier { #define ZT_DEFAULT_WORLD_LENGTH 634 static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x52,0x3c,0x32,0x50,0x1a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x4a,0xf7,0x86,0xa8,0x40,0xd6,0x52,0xea,0xae,0x9e,0x7a,0xbf,0x4c,0x97,0x66,0xab,0x2d,0x6f,0xaf,0xc9,0x2b,0x3a,0xff,0xed,0xd6,0x30,0x3e,0xc4,0x6a,0x65,0xf2,0xbd,0x83,0x52,0xf5,0x40,0xe9,0xcc,0x0d,0x6e,0x89,0x3f,0x9a,0xa0,0xb8,0xdf,0x42,0xd2,0x2f,0x84,0xe6,0x03,0x26,0x0f,0xa8,0xe3,0xcc,0x05,0x05,0x03,0xef,0x12,0x80,0x0d,0xce,0x3e,0xb6,0x58,0x3b,0x1f,0xa8,0xad,0xc7,0x25,0xf9,0x43,0x71,0xa7,0x5c,0x9a,0xc7,0xe1,0xa3,0xb8,0x88,0xd0,0x71,0x6c,0x94,0x99,0x73,0x41,0x0b,0x1b,0x48,0x84,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09}; -Topology::Topology(const RuntimeEnvironment *renv) : +Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : RR(renv), _trustedPathCount(0), _amRoot(false) { try { World cachedPlanet; - std::string buf(RR->node->dataStoreGet("planet")); + std::string buf(RR->node->dataStoreGet(tPtr,"planet")); if (buf.length() > 0) { Buffer dswtmp(buf.data(),(unsigned int)buf.length()); cachedPlanet.deserialize(dswtmp,0); } - addWorld(cachedPlanet,false); + addWorld(tPtr,cachedPlanet,false); } catch ( ... ) {} World defaultPlanet; @@ -75,10 +75,10 @@ Topology::Topology(const RuntimeEnvironment *renv) : Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top } - addWorld(defaultPlanet,false); + addWorld(tPtr,defaultPlanet,false); } -SharedPtr Topology::addPeer(const SharedPtr &peer) +SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { #ifdef ZT_TRACE if ((!peer)||(peer->address() == RR->identity.address())) { @@ -98,12 +98,12 @@ SharedPtr Topology::addPeer(const SharedPtr &peer) np = hp; } - saveIdentity(np->identity()); + saveIdentity(tPtr,np->identity()); return np; } -SharedPtr Topology::getPeer(const Address &zta) +SharedPtr Topology::getPeer(void *tPtr,const Address &zta) { if (zta == RR->identity.address()) { TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); @@ -118,7 +118,7 @@ SharedPtr Topology::getPeer(const Address &zta) } try { - Identity id(_getIdentity(zta)); + Identity id(_getIdentity(tPtr,zta)); if (id) { SharedPtr np(new Peer(RR,RR->identity,id)); { @@ -134,7 +134,7 @@ SharedPtr Topology::getPeer(const Address &zta) return SharedPtr(); } -Identity Topology::getIdentity(const Address &zta) +Identity Topology::getIdentity(void *tPtr,const Address &zta) { if (zta == RR->identity.address()) { return RR->identity; @@ -144,15 +144,15 @@ Identity Topology::getIdentity(const Address &zta) if (ap) return (*ap)->identity(); } - return _getIdentity(zta); + return _getIdentity(tPtr,zta); } -void Topology::saveIdentity(const Identity &id) +void Topology::saveIdentity(void *tPtr,const Identity &id) { if (id) { char p[128]; Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)id.address().toInt()); - RR->node->dataStorePut(p,id.toString(false),false); + RR->node->dataStorePut(tPtr,p,id.toString(false),false); } } @@ -264,7 +264,7 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa return false; } -bool Topology::addWorld(const World &newWorld,bool alwaysAcceptNew) +bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) { if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) return false; @@ -328,29 +328,29 @@ bool Topology::addWorld(const World &newWorld,bool alwaysAcceptNew) try { Buffer dswtmp; existing->serialize(dswtmp,false); - RR->node->dataStorePut(savePath,dswtmp.data(),dswtmp.size(),false); + RR->node->dataStorePut(tPtr,savePath,dswtmp.data(),dswtmp.size(),false); } catch ( ... ) { - RR->node->dataStoreDelete(savePath); + RR->node->dataStoreDelete(tPtr,savePath); } - _memoizeUpstreams(); + _memoizeUpstreams(tPtr); return true; } -void Topology::addMoon(const uint64_t id,const Address &seed) +void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) { char savePath[64]; Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); try { - std::string moonBin(RR->node->dataStoreGet(savePath)); + std::string moonBin(RR->node->dataStoreGet(tPtr,savePath)); if (moonBin.length() > 1) { Buffer wtmp(moonBin.data(),(unsigned int)moonBin.length()); World w; w.deserialize(wtmp); if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { - addWorld(w,true); + addWorld(tPtr,w,true); return; } } @@ -363,7 +363,7 @@ void Topology::addMoon(const uint64_t id,const Address &seed) } } -void Topology::removeMoon(const uint64_t id) +void Topology::removeMoon(void *tPtr,const uint64_t id) { Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l2(_peers_m); @@ -375,7 +375,7 @@ void Topology::removeMoon(const uint64_t id) } else { char savePath[64]; Utils::snprintf(savePath,sizeof(savePath),"moons.d/%.16llx.moon",id); - RR->node->dataStoreDelete(savePath); + RR->node->dataStoreDelete(tPtr,savePath); } } _moons.swap(nm); @@ -387,7 +387,7 @@ void Topology::removeMoon(const uint64_t id) } _moonSeeds.swap(cm); - _memoizeUpstreams(); + _memoizeUpstreams(tPtr); } void Topology::clean(uint64_t now) @@ -415,11 +415,11 @@ void Topology::clean(uint64_t now) } } -Identity Topology::_getIdentity(const Address &zta) +Identity Topology::_getIdentity(void *tPtr,const Address &zta) { char p[128]; Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)zta.toInt()); - std::string ids(RR->node->dataStoreGet(p)); + std::string ids(RR->node->dataStoreGet(tPtr,p)); if (ids.length() > 0) { try { return Identity(ids); @@ -428,7 +428,7 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } -void Topology::_memoizeUpstreams() +void Topology::_memoizeUpstreams(void *tPtr) { // assumes _upstreams_m and _peers_m are locked _upstreamAddresses.clear(); @@ -442,7 +442,7 @@ void Topology::_memoizeUpstreams() SharedPtr &hp = _peers[i->identity.address()]; if (!hp) { hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(i->identity); + saveIdentity(tPtr,i->identity); } } } @@ -456,7 +456,7 @@ void Topology::_memoizeUpstreams() SharedPtr &hp = _peers[i->identity.address()]; if (!hp) { hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(i->identity); + saveIdentity(tPtr,i->identity); } } } diff --git a/node/Topology.hpp b/node/Topology.hpp index e21747c8..4870ab5e 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -50,7 +50,7 @@ class RuntimeEnvironment; class Topology { public: - Topology(const RuntimeEnvironment *renv); + Topology(const RuntimeEnvironment *renv,void *tPtr); /** * Add a peer to database @@ -58,18 +58,20 @@ public: * This will not replace existing peers. In that case the existing peer * record is returned. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param peer Peer to add * @return New or existing peer (should replace 'peer') */ - SharedPtr addPeer(const SharedPtr &peer); + SharedPtr addPeer(void *tPtr,const SharedPtr &peer); /** * Get a peer from its address * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param zta ZeroTier address of peer * @return Peer or NULL if not found */ - SharedPtr getPeer(const Address &zta); + SharedPtr getPeer(void *tPtr,const Address &zta); /** * Get a peer only if it is presently in memory (no disk cache) @@ -109,10 +111,11 @@ public: /** * Get the identity of a peer * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param zta ZeroTier address of peer * @return Identity or NULL Identity if not found */ - Identity getIdentity(const Address &zta); + Identity getIdentity(void *tPtr,const Address &zta); /** * Cache an identity @@ -120,9 +123,10 @@ public: * This is done automatically on addPeer(), and so is only useful for * cluster identity replication. * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param id Identity to cache */ - void saveIdentity(const Identity &id); + void saveIdentity(void *tPtr,const Identity &id); /** * Get the current best upstream peer @@ -267,11 +271,12 @@ public: /** * Validate new world and update if newer and signature is okay * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param newWorld A new or updated planet or moon to learn * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one * @return True if it was valid and newer than current (or totally new for moons) */ - bool addWorld(const World &newWorld,bool alwaysAcceptNew); + bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew); /** * Add a moon @@ -282,14 +287,15 @@ public: * @param id Moon ID * @param seed If non-NULL, an address of any member of the moon to contact */ - void addMoon(const uint64_t id,const Address &seed); + void addMoon(void *tPtr,const uint64_t id,const Address &seed); /** * Remove a moon * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param id Moon's world ID */ - void removeMoon(const uint64_t id); + void removeMoon(void *tPtr,const uint64_t id); /** * Clean and flush database @@ -420,8 +426,8 @@ public: } private: - Identity _getIdentity(const Address &zta); - void _memoizeUpstreams(); + Identity _getIdentity(void *tPtr,const Address &zta); + void _memoizeUpstreams(void *tPtr); const RuntimeEnvironment *const RR; diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index 0e1ada6b..62fabc48 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -71,7 +71,7 @@ BSDEthernetTap::BSDEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : _handler(handler), _arg(arg), @@ -460,8 +460,7 @@ void BSDEthernetTap::threadMain() to.setTo(getBuf,6); from.setTo(getBuf + 6,6); unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); } r = 0; diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index 1bb48d31..8c6314db 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -43,7 +43,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~BSDEthernetTap(); @@ -62,7 +62,7 @@ public: throw(); private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; Thread _thread; diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index e7fe657f..c4b978e7 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -62,7 +62,7 @@ LinuxEthernetTap::LinuxEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : _handler(handler), _arg(arg), @@ -470,7 +470,7 @@ void LinuxEthernetTap::threadMain() from.setTo(getBuf + 6,6); unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); } r = 0; diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index 7dd7e01d..a2a00a79 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -44,7 +44,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~LinuxEthernetTap(); @@ -66,7 +66,7 @@ public: throw(); private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; Thread _thread; diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp index b3580929..35eac05a 100644 --- a/osdep/OSXEthernetTap.cpp +++ b/osdep/OSXEthernetTap.cpp @@ -314,7 +314,7 @@ OSXEthernetTap::OSXEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), void *arg) : _handler(handler), _arg(arg), @@ -646,7 +646,7 @@ void OSXEthernetTap::threadMain() from.setTo(getBuf + 6,6); unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); } r = 0; diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp index de48f9a4..5a96c210 100644 --- a/osdep/OSXEthernetTap.hpp +++ b/osdep/OSXEthernetTap.hpp @@ -48,7 +48,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~OSXEthernetTap(); @@ -67,7 +67,7 @@ public: throw(); private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; Thread _thread; diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 8ee088bb..79b9d35e 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -456,7 +456,7 @@ WindowsEthernetTap::WindowsEthernetTap( unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg) : _handler(handler), _arg(arg), @@ -1058,8 +1058,7 @@ void WindowsEthernetTap::threadMain() MAC from(tapReadBuf + 6,6); unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); try { - // TODO: decode vlans - _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); + _handler(_arg,(void *)0,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); } catch ( ... ) {} // handlers should not throw } } diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 53bba3e9..f2cf73f3 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -87,7 +87,7 @@ public: unsigned int metric, uint64_t nwid, const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void *arg); ~WindowsEthernetTap(); @@ -118,7 +118,7 @@ private: void _setRegistryIPv4Value(const char *regKey,const std::vector &value); void _syncIps(); - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; MAC _mac; uint64_t _nwid; diff --git a/service/OneService.cpp b/service/OneService.cpp index 22eefbb9..c07b3ba4 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -291,21 +291,21 @@ static void _moonToJson(nlohmann::json &mj,const World &world) class OneServiceImpl; -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); -static void SnodeEventCallback(ZT_Node *node,void *uptr,enum ZT_Event event,const void *metaData); -static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize); -static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure); -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); +static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); +static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); +static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize); +static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,const void *data,unsigned long len,int secure); +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); +static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); #ifdef ZT_ENABLE_CLUSTER static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len); static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr,int *x,int *y,int *z); #endif -static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); +static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); static int ShttpOnMessageBegin(http_parser *parser); static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); @@ -573,7 +573,7 @@ public: cb.eventCallback = SnodeEventCallback; cb.pathCheckFunction = SnodePathCheckFunction; cb.pathLookupFunction = SnodePathLookupFunction; - _node = new Node(this,&cb,OSUtils::now()); + _node = new Node(this,(void *)0,&cb,OSUtils::now()); } // Read local configuration @@ -804,7 +804,7 @@ public: for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".conf")) - _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0); + _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0,(void *)0); } } { // Load existing moons @@ -812,7 +812,7 @@ public: for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { std::size_t dot = f->find_last_of('.'); if ((dot == 16)&&(f->substr(16) == ".moon")) - _node->orbit(Utils::hexStrToU64(f->substr(0,dot).c_str()),0); + _node->orbit((void *)0,Utils::hexStrToU64(f->substr(0,dot).c_str()),0); } } @@ -877,7 +877,7 @@ public: uint64_t dl = _nextBackgroundTaskDeadline; if (dl <= now) { - _node->processBackgroundTasks(now,&_nextBackgroundTaskDeadline); + _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); dl = _nextBackgroundTaskDeadline; } @@ -892,7 +892,7 @@ public: std::vector added,removed; n->second.tap->scanMulticastGroups(added,removed); for(std::vector::iterator m(added.begin());m!=added.end();++m) - _node->multicastSubscribe(n->first,m->mac().toInt(),m->adi()); + _node->multicastSubscribe((void *)0,n->first,m->mac().toInt(),m->adi()); for(std::vector::iterator m(removed.begin());m!=removed.end();++m) _node->multicastUnsubscribe(n->first,m->mac().toInt(),m->adi()); } @@ -1306,7 +1306,7 @@ public: res["signature"] = json(); res["updatesMustBeSignedBy"] = json(); res["waiting"] = true; - _node->orbit(id,seed); + _node->orbit((void *)0,id,seed); scode = 200; } @@ -1315,7 +1315,7 @@ public: if (ps.size() == 2) { uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); - _node->join(wantnw,(void *)0); // does nothing if we are a member + _node->join(wantnw,(void *)0,(void *)0); // does nothing if we are a member ZT_VirtualNetworkList *nws = _node->networks(); if (nws) { for(unsigned long i=0;inetworkCount;++i) { @@ -1360,7 +1360,7 @@ public: if (ps[0] == "moon") { if (ps.size() == 2) { - _node->deorbit(Utils::hexStrToU64(ps[1].c_str())); + _node->deorbit((void *)0,Utils::hexStrToU64(ps[1].c_str())); res["result"] = true; scode = 200; } // else 404 @@ -1371,7 +1371,7 @@ public: uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); for(unsigned long i=0;inetworkCount;++i) { if (nws->networks[i].nwid == wantnw) { - _node->leave(wantnw,(void **)0); + _node->leave(wantnw,(void **)0,(void *)0); res["result"] = true; scode = 200; break; @@ -1693,6 +1693,7 @@ public: _lastDirectReceiveFromGlobal = OSUtils::now(); const ZT_ResultCode rc = _node->processWirePacket( + (void *)0, OSUtils::now(), reinterpret_cast(localAddr), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big @@ -1845,6 +1846,7 @@ public: if (from) { InetAddress fakeTcpLocalInterfaceAddress((uint32_t)0xffffffff,0xffff); const ZT_ResultCode rc = _node->processWirePacket( + (void *)0, OSUtils::now(), reinterpret_cast(&fakeTcpLocalInterfaceAddress), reinterpret_cast(&from), @@ -2255,7 +2257,7 @@ public: inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { - _node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); + _node->processVirtualNetworkFrame((void *)0,OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); } inline void onHttpRequestToServer(TcpConnection *tc) @@ -2426,21 +2428,21 @@ public: } }; -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) +static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) { return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } -static void SnodeEventCallback(ZT_Node *node,void *uptr,enum ZT_Event event,const void *metaData) +static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) { reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } -static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize) +static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize) { return reinterpret_cast(uptr)->nodeDataStoreGetFunction(name,buf,bufSize,readIndex,totalSize); } -static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure) +static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,void *tptr,const char *name,const void *data,unsigned long len,int secure) { return reinterpret_cast(uptr)->nodeDataStorePutFunction(name,data,len,secure); } -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) { return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) { return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } #ifdef ZT_ENABLE_CLUSTER @@ -2458,7 +2460,7 @@ static int SclusterGeoIpFunction(void *uptr,const struct sockaddr_storage *addr, } #endif -static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } static int ShttpOnMessageBegin(http_parser *parser) diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 7ecd42b1..7ec377cc 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -175,7 +175,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void std::string lj; lj.push_back((char)VERB_LATEST); lj.append(OSUtils::jsonDump(*latest)); - _node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length()); + _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length()); if (_distLog) { fprintf(_distLog,"%.10llx GET_LATEST %u.%u.%u_%u platform %u arch %u vendor %u channel %s -> LATEST %u.%u.%u_%u" ZT_EOL_S,(unsigned long long)origin,rvMaj,rvMin,rvRev,rvBld,rvPlatform,rvArch,rvVendor,rvChannel.c_str(),bestVMaj,bestVMin,bestVRev,bestVBld); fflush(_distLog); @@ -205,7 +205,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append((uint8_t)VERB_GET_DATA); gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -229,7 +229,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void buf.append(reinterpret_cast(data) + 1,16); buf.append((uint32_t)idx); buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx))); - _node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); + _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); //printf(">> DATA @%u\n",(unsigned int)idx); } } @@ -249,7 +249,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void gd.append((uint8_t)VERB_GET_DATA); gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -296,7 +296,7 @@ bool SoftwareUpdater::check(const uint64_t now) ZT_BUILD_ARCHITECTURE, (int)ZT_VENDOR_ZEROTIER, _channel.c_str()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); //printf(">> GET_LATEST\n"); } @@ -343,7 +343,7 @@ bool SoftwareUpdater::check(const uint64_t now) gd.append((uint8_t)VERB_GET_DATA); gd.append(_downloadHashPrefix.data,16); gd.append((uint32_t)_download.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); //printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } -- cgit v1.2.3 From 91c9f4cb205169d0ec151293136aa27d113f2090 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Mar 2017 17:33:25 -0700 Subject: Fix TRACE and CLUSTER builds. --- node/Cluster.cpp | 14 +++++++------- node/Node.cpp | 4 ++-- node/Peer.cpp | 4 ++-- node/Switch.cpp | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 52e03ffe..54206f99 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -346,7 +346,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) Mutex::Lock _l(_remotePeers_m); _RemotePeer &rp = _remotePeers[std::pair(id.address(),(unsigned int)fromMemberId)]; if (!rp.lastHavePeerReceived) { - RR->topology->saveIdentity(id); + RR->topology->saveIdentity((void *)0,id); RR->identity.agree(id,rp.key,ZT_PEER_SECRET_KEY_LENGTH); } rp.lastHavePeerReceived = RR->node->now(); @@ -459,7 +459,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) Mutex::Lock _l2(_members[fromMemberId].lock); _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,rendezvousForRemote.data(),rendezvousForRemote.size()); } - RR->sw->send(rendezvousForLocal,true); + RR->sw->send((void *)0,rendezvousForLocal,true); } } } break; @@ -470,7 +470,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) const unsigned int len = dmsg.at(ptr); ptr += 2; Packet outp(rcpt,RR->identity.address(),verb); outp.append(dmsg.field(ptr,len),len); ptr += len; - RR->sw->send(outp,true); + RR->sw->send((void *)0,outp,true); //TRACE("[%u] proxy send %s to %s length %u",(unsigned int)fromMemberId,Packet::verbString(verb),rcpt.toString().c_str(),len); } break; @@ -479,7 +479,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) if (network) { // Copy into a Packet just to conform to Network API. Eventually // will want to refactor. - network->handleConfigChunk(0,Address(),Buffer(dmsg),ptr); + network->handleConfigChunk((void *)0,0,Address(),Buffer(dmsg),ptr); } } break; } @@ -576,7 +576,7 @@ bool Cluster::sendViaCluster(int mostRecentMemberId,const Address &toPeerAddress for(std::vector::const_iterator i2(_members[mostRecentMemberId].zeroTierPhysicalEndpoints.begin());i2!=_members[mostRecentMemberId].zeroTierPhysicalEndpoints.end();++i2) { if (i1->ss_family == i2->ss_family) { TRACE("sendViaCluster sending %u bytes to %s by way of %u (%s->%s)",len,toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId,i1->toString().c_str(),i2->toString().c_str()); - RR->node->putPacket(*i1,*i2,data,len); + RR->node->putPacket((void *)0,*i1,*i2,data,len); return true; } } @@ -679,7 +679,7 @@ void Cluster::relayViaCluster(const Address &fromPeerAddress,const Address &toPe for(std::vector::const_iterator i2(_members[mostRecentMemberId].zeroTierPhysicalEndpoints.begin());i2!=_members[mostRecentMemberId].zeroTierPhysicalEndpoints.end();++i2) { if (i1->ss_family == i2->ss_family) { TRACE("relayViaCluster relaying %u bytes from %s to %s by way of %u (%s->%s)",len,fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId,i1->toString().c_str(),i2->toString().c_str()); - RR->node->putPacket(*i1,*i2,data,len); + RR->node->putPacket((void *)0,*i1,*i2,data,len); return; } } @@ -981,7 +981,7 @@ void Cluster::_flush(uint16_t memberId) void Cluster::_doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep) { if (remotep.payloadLength() >= ZT_ADDRESS_LENGTH) { - Identity queried(RR->topology->getIdentity(Address(remotep.payload(),ZT_ADDRESS_LENGTH))); + Identity queried(RR->topology->getIdentity((void *)0,Address(remotep.payload(),ZT_ADDRESS_LENGTH))); if (queried) { Buffer<1024> routp; remotep.source().appendTo(routp); diff --git a/node/Node.cpp b/node/Node.cpp index 4e8d6655..e7dc637f 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -285,7 +285,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint #ifdef ZT_ENABLE_CLUSTER // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior if (RR->cluster) { - RR->sw->doTimerTasks(now); + RR->sw->doTimerTasks(tptr,now); RR->cluster->doPeriodicTasks(); *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate } else { @@ -686,7 +686,7 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) tmp2[sizeof(tmp2)-1] = (char)0; Utils::snprintf(tmp1,sizeof(tmp1),"[%s] %s:%u %s",nowstr,module,line,tmp2); - postEvent(ZT_EVENT_TRACE,tmp1); + postEvent((void *)0,ZT_EVENT_TRACE,tmp1); } #endif // ZT_TRACE diff --git a/node/Peer.cpp b/node/Peer.cpp index 0cc23e33..0795a6ea 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -103,7 +103,7 @@ void Peer::received( } outp.append((uint16_t)redirectTo.port()); outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,outp.data(),outp.size(),now); + path->send(RR,tPtr,outp.data(),outp.size(),now); } else { // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -118,7 +118,7 @@ void Peer::received( outp.append(redirectTo.rawIpData(),16); } outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,outp.data(),outp.size(),now); + path->send(RR,tPtr,outp.data(),outp.size(),now); } suboptimalPath = true; } diff --git a/node/Switch.cpp b/node/Switch.cpp index 62674472..56299a9a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -863,7 +863,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) Packet::Fragment frag(packet,fragStart,chunkSize,fno,totalFragments); #ifdef ZT_ENABLE_CLUSTER if (viaPath) - viaPath->send(RR,frag.data(),frag.size(),now); + viaPath->send(RR,tPtr,frag.data(),frag.size(),now); else if (clusterMostRecentMemberId >= 0) RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,frag.data(),frag.size()); #else -- cgit v1.2.3 From 139c4b56337c0cfe7458ecf5df4e12e38c2d4f8a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 14 Apr 2017 17:53:32 -0700 Subject: Significant simplification to path logic. --- node/Constants.hpp | 2 +- node/IncomingPacket.cpp | 32 +++--- node/Node.cpp | 18 ++-- node/Peer.cpp | 273 +++++++++++++++++++----------------------------- node/Peer.hpp | 119 +++++++++------------ node/Topology.hpp | 4 +- 6 files changed, 182 insertions(+), 266 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 410a245b..93184efa 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -289,7 +289,7 @@ #define ZT_PEER_PING_PERIOD 60000 /** - * Paths are considered expired if they have not produced a real packet in this long + * Paths are considered expired if they have not sent us a real packet in this long */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 52794fd7..a0f5ee1d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1200,16 +1200,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt switch(addrType) { case 4: { - InetAddress a(field(ptr,4),4,at(ptr + 4)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { + const InetAddress a(field(ptr,4),4,at(ptr + 4)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + { if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); @@ -1219,16 +1215,12 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt } } break; case 6: { - InetAddress a(field(ptr,16),16,at(ptr + 16)); - - bool redundant = false; - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->setClusterOptimal(a); - } else { - redundant = peer->hasActivePathTo(now,a); - } - - if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) { + const InetAddress a(field(ptr,16),16,at(ptr + 16)); + if ( + ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + { if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Node.cpp b/node/Node.cpp index 9844b09e..1bc96cca 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -407,17 +407,17 @@ ZT_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->role(pi->second->identity().address()); - std::vector< std::pair< SharedPtr,bool > > paths(pi->second->paths(_now)); + std::vector< SharedPtr > paths(pi->second->paths(_now)); SharedPtr bestp(pi->second->getBestPath(_now,false)); p->pathCount = 0; - for(std::vector< std::pair< SharedPtr,bool > >::iterator path(paths.begin());path!=paths.end();++path) { - memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].lastSend = path->first->lastOut(); - p->paths[p->pathCount].lastReceive = path->first->lastIn(); - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address()); - p->paths[p->pathCount].linkQuality = (int)path->first->linkQuality(); - p->paths[p->pathCount].expired = path->second; - p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0; + for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { + memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); + p->paths[p->pathCount].lastSend = (*path)->lastOut(); + p->paths[p->pathCount].lastReceive = (*path)->lastIn(); + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); + p->paths[p->pathCount].linkQuality = (int)(*path)->linkQuality(); + p->paths[p->pathCount].expired = 0; + p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; ++p->pathCount; } } diff --git a/node/Peer.cpp b/node/Peer.cpp index 0795a6ea..2711dd19 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,14 +27,6 @@ #include "Cluster.hpp" #include "Packet.hpp" -#ifndef AF_MAX -#if AF_INET > AF_INET6 -#define AF_MAX AF_INET -#else -#define AF_MAX AF_INET6 -#endif -#endif - namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : @@ -51,18 +43,15 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), - _remoteClusterOptimal4(0), _vProto(0), _vMajor(0), _vMinor(0), _vRevision(0), _id(peerIdentity), - _numPaths(0), _latency(0), _directPathPushCutoffCount(0), _credentialsCutoffCount(0) { - memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6)); if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); } @@ -80,7 +69,7 @@ void Peer::received( const uint64_t now = RR->node->now(); #ifdef ZT_ENABLE_CLUSTER - bool suboptimalPath = false; + bool isClusterSuboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { // Note: findBetterEndpoint() is first since we still want to check // for a better endpoint even if we don't actually send a redirect. @@ -146,65 +135,60 @@ void Peer::received( path->updateLinkQuality((unsigned int)(packetId & 7)); if (hops == 0) { - bool pathIsConfirmed = false; + bool pathAlreadyKnown = false; { Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address() == path->address()) { - _paths[p].lastReceive = now; - _paths[p].path = path; // local address may have changed! + if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { + const struct sockaddr_in *const r = reinterpret_cast(&(path->address())); + const struct sockaddr_in *const l = reinterpret_cast(&(_v4Path.p->address())); + const struct sockaddr_in *const rl = reinterpret_cast(&(path->localAddress())); + const struct sockaddr_in *const ll = reinterpret_cast(&(_v4Path.p->localAddress())); + if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { + _v4Path.lr = now; #ifdef ZT_ENABLE_CLUSTER - _paths[p].localClusterSuboptimal = suboptimalPath; + _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; #endif - pathIsConfirmed = true; - break; + pathAlreadyKnown = true; + } + } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { + const struct sockaddr_in6 *const r = reinterpret_cast(&(path->address())); + const struct sockaddr_in6 *const l = reinterpret_cast(&(_v6Path.p->address())); + const struct sockaddr_in6 *const rl = reinterpret_cast(&(path->localAddress())); + const struct sockaddr_in6 *const ll = reinterpret_cast(&(_v6Path.p->localAddress())); + if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { + _v6Path.lr = now; +#ifdef ZT_ENABLE_CLUSTER + _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; +#endif + pathAlreadyKnown = true; } } } - if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); - - // Since this is a new path, figure out where to put it (possibly replacing an old/dead one) - unsigned int slot; - if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { - slot = _numPaths++; - } else { - // First try to replace the worst within the same address family, if possible - int worstSlot = -1; - uint64_t worstScore = 0xffffffffffffffffULL; - for(unsigned int p=0;p<_numPaths;++p) { - if (_paths[p].path->address().ss_family == path->address().ss_family) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - worstSlot = (int)p; - } - } - } - if (worstSlot >= 0) { - slot = (unsigned int)worstSlot; - } else { - // If we can't find one with the same family, replace the worst of any family - slot = ZT_MAX_PEER_NETWORK_PATHS - 1; - for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p,now); - if (s < worstScore) { - worstScore = s; - slot = p; - } - } + if (path->address().ss_family == AF_INET) { + if ((!_v4Path.p)||(!_v4Path.p->alive(now))||(path->preferenceRank() >= _v4Path.p->preferenceRank())) { + _v4Path.lr = now; + _v4Path.p = path; +#ifdef ZT_ENABLE_CLUSTER + _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); +#endif } - } - - _paths[slot].lastReceive = now; - _paths[slot].path = path; + } else if (path->address().ss_family == AF_INET6) { + if ((!_v6Path.p)||(!_v6Path.p->alive(now))||(path->preferenceRank() >= _v6Path.p->preferenceRank())) { + _v6Path.lr = now; + _v6Path.p = path; #ifdef ZT_ENABLE_CLUSTER - _paths[slot].localClusterSuboptimal = suboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); + _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); #endif + } + } } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -214,10 +198,10 @@ void Peer::received( } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) #ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - const bool haveCluster = (RR->cluster); + // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection + const bool haveCluster = (RR->cluster); #else - const bool haveCluster = false; + const bool haveCluster = false; #endif if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { _lastDirectPathPushSent = now; @@ -290,60 +274,50 @@ void Peer::received( } } -bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) - return true; - } - return false; -} - -bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } + uint64_t v6lr = 0; + if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if ( (v6lr > v4lr) && ((now - v6lr) < ZT_PATH_ALIVE_TIMEOUT) ) { + return _v6Path.p->send(RR,tPtr,data,len,now); + } else if ((now - v4lr) < ZT_PATH_ALIVE_TIMEOUT) { + return _v4Path.p->send(RR,tPtr,data,len,now); + } else if (force) { + if (v6lr > v4lr) { + return _v6Path.p->send(RR,tPtr,data,len,now); + } else if (v4lr) { + return _v4Path.p->send(RR,tPtr,data,len,now); } } - if (bestp >= 0) { - return _paths[bestp].path->send(RR,tPtr,data,len,now); - } else { - return false; - } + return false; } SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; - } - } + uint64_t v6lr = 0; + if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if (v6lr > v4lr) { + return _v6Path.p; + } else if (v4lr) { + return _v4Path.p; } - if (bestp >= 0) { - return _paths[bestp].path; - } else { - return SharedPtr(); - } + return SharedPtr(); } void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) @@ -420,79 +394,44 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); - int bestp = -1; - uint64_t best = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) { - const uint64_t s = _pathScore(p,now); - if (s >= best) { - best = s; - bestp = (int)p; + if (inetAddressFamily < 0) { + uint64_t v6lr = 0; + if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) + v6lr = _v6Path.p->lastIn(); + uint64_t v4lr = 0; + if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) + v4lr = _v4Path.p->lastIn(); + + if (v6lr > v4lr) { + if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + return true; + } + } else if (v4lr) { + if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + return true; } } - } - - if (bestp >= 0) { - if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter()); - _paths[bestp].path->sent(now); - } - return true; } else { - return false; - } -} - -bool Peer::hasActiveDirectPath(uint64_t now) const -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now))) - return true; - } - return false; -} - -void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) -{ - Mutex::Lock _l(_paths_m); - for(unsigned int p=0;p<_numPaths;++p) { - if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) { - attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter()); - _paths[p].path->sent(now); - _paths[p].lastReceive = 0; // path will not be used unless it speaks again - } - } -} - -void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const -{ - Mutex::Lock _l(_paths_m); - - int bestp4 = -1,bestp6 = -1; - uint64_t best4 = 0ULL,best6 = 0ULL; - for(unsigned int p=0;p<_numPaths;++p) { - if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) { - if (_paths[p].path->address().ss_family == AF_INET) { - const uint64_t s = _pathScore(p,now); - if (s >= best4) { - best4 = s; - bestp4 = (int)p; - } - } else if (_paths[p].path->address().ss_family == AF_INET6) { - const uint64_t s = _pathScore(p,now); - if (s >= best6) { - best6 = s; - bestp6 = (int)p; - } + if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { + if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + return true; + } + } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { + if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + return true; } } } - if (bestp4 >= 0) - v4 = _paths[bestp4].path->address(); - if (bestp6 >= 0) - v6 = _paths[bestp6].path->address(); + return false; } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 41836410..f225eb85 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -108,20 +108,10 @@ public: * @param addr Remote address * @return True if we have an active path to this destination */ - bool hasActivePathTo(uint64_t now,const InetAddress &addr) const; - - /** - * Set which known path for an address family is optimal - * - * @param addr Address to make exclusive - */ - inline void setClusterOptimal(const InetAddress &addr) + inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const { - if (addr.ss_family == AF_INET) { - _remoteClusterOptimal4 = (uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr; - } else if (addr.ss_family == AF_INET6) { - memcpy(_remoteClusterOptimal6,reinterpret_cast(&addr)->sin6_addr.s6_addr,16); - } + Mutex::Lock _l(_paths_m); + return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); } /** @@ -131,14 +121,17 @@ public: * @param data Packet data * @param len Packet length * @param now Current time - * @param forceEvenIfDead If true, send even if the path is not 'alive' + * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead); + bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force); /** * Get the best current direct path * + * This does not check Path::alive(), but does return the most recently + * active path and does check expiration (which is a longer timeout). + * * @param now Current time * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none @@ -192,12 +185,6 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); - /** - * @param now Current time - * @return True if this peer has at least one active and alive direct path - */ - bool hasActiveDirectPath(uint64_t now) const; - /** * Reset paths within a given IP scope and address family * @@ -209,30 +196,48 @@ public: * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now); + inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) + { + Mutex::Lock _l(_paths_m); + if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { + attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + _v4Path.p->sent(now); + _v4Path.lr = 0; // path will not be used unless it speaks again + } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { + attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + _v6Path.p->sent(now); + _v6Path.lr = 0; // path will not be used unless it speaks again + } + } /** - * Get most recently active path addresses for IPv4 and/or IPv6 - * - * Note that v4 and v6 are not modified if they are not found, so - * initialize these to a NULL address to be able to check. + * Fill parameters with V4 and V6 addresses if known and alive * * @param now Current time * @param v4 Result parameter to receive active IPv4 address, if any * @param v6 Result parameter to receive active IPv6 address, if any */ - void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const + { + Mutex::Lock _l(_paths_m); + if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) + v4 = _v4Path.p->address(); + if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) + v6 = _v6Path.p->address(); + } /** * @param now Current time - * @return All known direct paths to this peer and whether they are expired (true == expired) + * @return All known paths to this peer */ - inline std::vector< std::pair< SharedPtr,bool > > paths(const uint64_t now) const + inline std::vector< SharedPtr > paths(const uint64_t now) const { - std::vector< std::pair< SharedPtr,bool > > pp; + std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); - for(unsigned int p=0,np=_numPaths;p,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION)); + if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) + pp.push_back(_v4Path.p); + if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) + pp.push_back(_v6Path.p); return pp; } @@ -424,32 +429,19 @@ public: } private: - inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const + struct _PeerPath { - uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)); - - if (_paths[p].path->address().ss_family == AF_INET) { - s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4)); - } else if (_paths[p].path->address().ss_family == AF_INET6) { - uint64_t clusterWeight = ZT_PEER_PING_PERIOD; - const uint8_t *a = reinterpret_cast(reinterpret_cast(&(_paths[p].path->address()))->sin6_addr.s6_addr); - for(long i=0;i<16;++i) { - if (a[i] != _remoteClusterOptimal6[i]) { - clusterWeight = 0; - break; - } - } - s += clusterWeight; - } - - s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now); - #ifdef ZT_ENABLE_CLUSTER - s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal; + _PeerPath() : lr(0),p(),localClusterSuboptimal(false) {} +#else + _PeerPath() : lr(0),p() {} #endif - - return s; - } + uint64_t lr; // time of last valid ZeroTier packet + SharedPtr p; +#ifdef ZT_ENABLE_CLUSTER + bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer +#endif + }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -468,26 +460,17 @@ private: uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; - uint8_t _remoteClusterOptimal6[16]; - uint32_t _remoteClusterOptimal4; - uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; - Identity _id; - - struct { - uint64_t lastReceive; - SharedPtr path; -#ifdef ZT_ENABLE_CLUSTER - bool localClusterSuboptimal; -#endif - } _paths[ZT_MAX_PEER_NETWORK_PATHS]; + _PeerPath _v4Path; // IPv4 direct path + _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; - unsigned int _numPaths; + Identity _id; + unsigned int _latency; unsigned int _directPathPushCutoffCount; unsigned int _credentialsCutoffCount; diff --git a/node/Topology.hpp b/node/Topology.hpp index 4870ab5e..d29c424e 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -314,7 +314,9 @@ public: Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - cnt += (unsigned long)((*p)->hasActiveDirectPath(now)); + const SharedPtr pp((*p)->getBestPath(now,false)); + if ((pp)&&(pp->alive(now))) + ++cnt; } return cnt; } -- cgit v1.2.3 From f1c0563c40dc9e3ec5e975d3e1e8d6057ed6bd83 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 14 Apr 2017 18:02:04 -0700 Subject: Fix for cluster handoff. --- node/IncomingPacket.cpp | 4 ++++ node/Peer.cpp | 4 ++-- node/Peer.hpp | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a0f5ee1d..303160ec 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1206,6 +1206,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + peer->setClusterPreferred(a); if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); @@ -1221,6 +1223,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + peer->setClusterPreferred(a); if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Peer.cpp b/node/Peer.cpp index 2711dd19..7ffe8926 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -169,7 +169,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); if (path->address().ss_family == AF_INET) { - if ((!_v4Path.p)||(!_v4Path.p->alive(now))||(path->preferenceRank() >= _v4Path.p->preferenceRank())) { + if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) { _v4Path.lr = now; _v4Path.p = path; #ifdef ZT_ENABLE_CLUSTER @@ -179,7 +179,7 @@ void Peer::received( #endif } } else if (path->address().ss_family == AF_INET6) { - if ((!_v6Path.p)||(!_v6Path.p->alive(now))||(path->preferenceRank() >= _v6Path.p->preferenceRank())) { + if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) { _v6Path.lr = now; _v6Path.p = path; #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Peer.hpp b/node/Peer.hpp index f225eb85..6cf30feb 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -210,6 +210,19 @@ public: } } + /** + * Indicate that the given address was provided by a cluster as a preferred destination + * + * @param addr Address cluster prefers that we use + */ + inline void setClusterPreferred(const InetAddress &addr) + { + if (addr.ss_family == AF_INET) + _v4ClusterPreferred = addr; + else if (addr.ss_family == AF_INET6) + _v6ClusterPreferred = addr; + } + /** * Fill parameters with V4 and V6 addresses if known and alive * @@ -465,6 +478,9 @@ private: uint16_t _vMinor; uint16_t _vRevision; + InetAddress _v4ClusterPreferred; + InetAddress _v6ClusterPreferred; + _PeerPath _v4Path; // IPv4 direct path _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; -- cgit v1.2.3 From 2487a8bede10f1ea58ca2778d9772ee9056e6b12 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Apr 2017 09:14:21 -0700 Subject: Fix for 100% cpu issue. --- node/Peer.cpp | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index 7ffe8926..827dc7de 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -166,33 +166,31 @@ void Peer::received( } if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { - if (verb == Packet::VERB_OK) { - Mutex::Lock _l(_paths_m); - if (path->address().ss_family == AF_INET) { - if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) { - _v4Path.lr = now; - _v4Path.p = path; -#ifdef ZT_ENABLE_CLUSTER - _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); -#endif - } - } else if (path->address().ss_family == AF_INET6) { - if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) { - _v6Path.lr = now; - _v6Path.p = path; + Mutex::Lock _l(_paths_m); + _PeerPath *potentialNewPeerPath = (_PeerPath *)0; + if (path->address().ss_family == AF_INET) { + if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) { + potentialNewPeerPath = &_v4Path; + } + } else if (path->address().ss_family == AF_INET6) { + if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) { + potentialNewPeerPath = &_v6Path; + } + } + if (potentialNewPeerPath) { + if (verb == Packet::VERB_OK) { + potentialNewPeerPath->lr = now; + potentialNewPeerPath->p = path; #ifdef ZT_ENABLE_CLUSTER - _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); + potentialNewPeerPath->localClusterSuboptimal = isClusterSuboptimalPath; + if (RR->cluster) + RR->cluster->broadcastHavePeer(_id); #endif - } + } else { + TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); + attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); + path->sent(now); } - } else { - TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); } } } else if (this->trustEstablished(now)) { -- cgit v1.2.3 From 95e5345cc37316c264c8d3d732d324c60f18ab72 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Apr 2017 10:12:13 -0700 Subject: Cluster build fix. --- node/Peer.cpp | 2 +- node/Peer.hpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index 827dc7de..2e9f6a2b 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -109,7 +109,7 @@ void Peer::received( outp.armor(_key,true,path->nextOutgoingCounter()); path->send(RR,tPtr,outp.data(),outp.size(),now); } - suboptimalPath = true; + isClusterSuboptimalPath = true; } } #endif diff --git a/node/Peer.hpp b/node/Peer.hpp index 6cf30feb..b9d85404 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -316,11 +316,8 @@ public: */ inline bool hasLocalClusterOptimalPath(uint64_t now) const { - for(unsigned int p=0,np=_numPaths;palive(now)) && (!_paths[p].localClusterSuboptimal) ) - return true; - } - return false; + Mutex::Lock _l(_paths_m); + return ( ((_v4Path.p)&&(_v4Path.p->alive(now))&&(!_v4Path.localClusterSuboptimal)) || ((_v6Path.p)&&(_v6Path.p->alive(now))&&(!_v6Path.localClusterSuboptimal)) ); } #endif -- cgit v1.2.3 From 1b68d6dbdc5540e1b26b4ea35d019dde746af79e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 27 Apr 2017 20:47:25 -0700 Subject: License header update. --- include/ZeroTierOne.h | 10 +++++++++- node/Address.hpp | 10 +++++++++- node/Array.hpp | 10 +++++++++- node/AtomicCounter.hpp | 10 +++++++++- node/Buffer.hpp | 10 +++++++++- node/C25519.cpp | 4 +--- node/C25519.hpp | 10 +++++++++- node/Capability.cpp | 10 +++++++++- node/Capability.hpp | 10 +++++++++- node/CertificateOfMembership.cpp | 10 +++++++++- node/CertificateOfMembership.hpp | 10 +++++++++- node/CertificateOfOwnership.cpp | 10 +++++++++- node/CertificateOfOwnership.hpp | 10 +++++++++- node/CertificateOfRepresentation.hpp | 10 +++++++++- node/Cluster.cpp | 10 +++++++++- node/Cluster.hpp | 10 +++++++++- node/Constants.hpp | 10 +++++++++- node/Credential.hpp | 10 +++++++++- node/Dictionary.hpp | 10 +++++++++- node/Hashtable.hpp | 10 +++++++++- node/Identity.cpp | 10 +++++++++- node/Identity.hpp | 10 +++++++++- node/IncomingPacket.cpp | 10 +++++++++- node/IncomingPacket.hpp | 10 +++++++++- node/InetAddress.cpp | 10 +++++++++- node/InetAddress.hpp | 10 +++++++++- node/MAC.hpp | 10 +++++++++- node/Membership.cpp | 10 +++++++++- node/Membership.hpp | 10 +++++++++- node/MulticastGroup.hpp | 10 +++++++++- node/Multicaster.cpp | 10 +++++++++- node/Multicaster.hpp | 10 +++++++++- node/Mutex.hpp | 10 +++++++++- node/Network.cpp | 10 +++++++++- node/Network.hpp | 10 +++++++++- node/NetworkConfig.cpp | 10 +++++++++- node/NetworkConfig.hpp | 10 +++++++++- node/NetworkController.hpp | 10 +++++++++- node/Node.cpp | 10 +++++++++- node/Node.hpp | 10 +++++++++- node/NonCopyable.hpp | 10 +++++++++- node/OutboundMulticast.cpp | 10 +++++++++- node/OutboundMulticast.hpp | 10 +++++++++- node/Packet.cpp | 10 +++++++++- node/Packet.hpp | 10 +++++++++- node/Path.cpp | 10 +++++++++- node/Path.hpp | 10 +++++++++- node/Peer.cpp | 10 +++++++++- node/Peer.hpp | 10 +++++++++- node/Poly1305.hpp | 10 +++++++++- node/Revocation.cpp | 10 +++++++++- node/Revocation.hpp | 10 +++++++++- node/RuntimeEnvironment.hpp | 10 +++++++++- node/SHA512.cpp | 35 +++++++---------------------------- node/SHA512.hpp | 10 +++++++++- node/SelfAwareness.cpp | 10 +++++++++- node/SelfAwareness.hpp | 10 +++++++++- node/SharedPtr.hpp | 10 +++++++++- node/Switch.cpp | 10 +++++++++- node/Switch.hpp | 10 +++++++++- node/Tag.cpp | 10 +++++++++- node/Tag.hpp | 10 +++++++++- node/Topology.cpp | 10 +++++++++- node/Topology.hpp | 10 +++++++++- node/Utils.cpp | 10 +++++++++- node/Utils.hpp | 10 +++++++++- node/World.hpp | 10 +++++++++- one.cpp | 10 +++++++++- osdep/Arp.cpp | 10 +++++++++- osdep/Arp.hpp | 10 +++++++++- osdep/BSDEthernetTap.cpp | 10 +++++++++- osdep/BSDEthernetTap.hpp | 10 +++++++++- osdep/Binder.hpp | 10 +++++++++- osdep/BlockingQueue.hpp | 10 +++++++++- osdep/Http.cpp | 10 +++++++++- osdep/Http.hpp | 10 +++++++++- osdep/LinuxEthernetTap.cpp | 10 +++++++++- osdep/LinuxEthernetTap.hpp | 10 +++++++++- osdep/ManagedRoute.cpp | 10 +++++++++- osdep/ManagedRoute.hpp | 26 ++++++++++++++++++++++++++ osdep/NeighborDiscovery.cpp | 10 +++++++++- osdep/NeighborDiscovery.hpp | 10 +++++++++- osdep/OSUtils.cpp | 10 +++++++++- osdep/OSUtils.hpp | 10 +++++++++- osdep/OSXEthernetTap.cpp | 10 +++++++++- osdep/OSXEthernetTap.hpp | 10 +++++++++- osdep/Phy.hpp | 10 +++++++++- osdep/PortMapper.cpp | 10 +++++++++- osdep/PortMapper.hpp | 10 +++++++++- osdep/TestEthernetTap.hpp | 10 +++++++++- osdep/Thread.hpp | 10 +++++++++- osdep/WindowsEthernetTap.cpp | 10 +++++++++- osdep/WindowsEthernetTap.hpp | 10 +++++++++- selftest.cpp | 10 +++++++++- service/ClusterDefinition.hpp | 10 +++++++++- service/ClusterGeoIpService.cpp | 10 +++++++++- service/ClusterGeoIpService.hpp | 10 +++++++++- service/OneService.cpp | 10 +++++++++- service/OneService.hpp | 10 +++++++++- service/SoftwareUpdater.cpp | 10 +++++++++- service/SoftwareUpdater.hpp | 10 +++++++++- version.h | 10 +++++++++- 102 files changed, 925 insertions(+), 130 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 747e1855..20707a1d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ /* diff --git a/node/Address.hpp b/node/Address.hpp index 4a5883b0..9d2d1734 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ADDRESS_HPP diff --git a/node/Array.hpp b/node/Array.hpp index 19b29eb3..5c616475 100644 --- a/node/Array.hpp +++ b/node/Array.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ARRAY_HPP diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index a0f29baa..e1864db8 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ATOMICCOUNTER_HPP diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 37f39e7b..ae242c73 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BUFFER_HPP diff --git a/node/C25519.cpp b/node/C25519.cpp index e9ffecc1..a78e0466 100644 --- a/node/C25519.cpp +++ b/node/C25519.cpp @@ -1,5 +1,3 @@ -// Code taken from NaCl by D. J. Bernstein and others - /* Matthew Dempsky Public domain. @@ -7,7 +5,7 @@ Derived from public domain code by D. J. Bernstein. */ // Modified very slightly for ZeroTier One by Adam Ierymenko -// (no functional changes) +// This code remains in the public domain. #include #include diff --git a/node/C25519.hpp b/node/C25519.hpp index b19d9693..da9ba665 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_C25519_HPP diff --git a/node/Capability.cpp b/node/Capability.cpp index c178e566..0e02025a 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Capability.hpp" diff --git a/node/Capability.hpp b/node/Capability.hpp index 454723ac..8d4b9085 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CAPABILITY_HPP diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 9bf70216..a5445e42 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "CertificateOfMembership.hpp" diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index dfccb138..739d5390 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 2bd181e0..31d0ae18 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "CertificateOfOwnership.hpp" diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index f01da38e..95039a2d 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp index 710ee577..92a71bc0 100644 --- a/node/CertificateOfRepresentation.hpp +++ b/node/CertificateOfRepresentation.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 54206f99..4d2dea76 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_ENABLE_CLUSTER diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 08e32a99..74b091f5 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CLUSTER_HPP diff --git a/node/Constants.hpp b/node/Constants.hpp index 93184efa..d3c87491 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CONSTANTS_HPP diff --git a/node/Credential.hpp b/node/Credential.hpp index 0ae2a0a8..bc81919b 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CREDENTIAL_HPP diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 0db13b63..e212e453 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_DICTIONARY_HPP diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 66f2990a..c46ed68f 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_HASHTABLE_HPP diff --git a/node/Identity.cpp b/node/Identity.cpp index d1b21e9c..ba77aa47 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Identity.hpp b/node/Identity.hpp index e4522732..b1c7d6f4 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_IDENTITY_HPP diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 303160ec..126da53c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 3d4a2e05..43a1ea10 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_INCOMINGPACKET_HPP diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 7d22eeae..62bb8145 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index c37fa621..0975a9cf 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_INETADDRESS_HPP diff --git a/node/MAC.hpp b/node/MAC.hpp index 95623f12..e7717d99 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MAC_HPP diff --git a/node/Membership.cpp b/node/Membership.cpp index 2d0471f1..466f9021 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Membership.hpp b/node/Membership.hpp index 0bc8f335..5e4475da 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MEMBERSHIP_HPP diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index be4e8084..4240db67 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MULTICASTGROUP_HPP diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 8e534b5e..52213364 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index f646a5be..2186e9c3 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MULTICASTER_HPP diff --git a/node/Mutex.hpp b/node/Mutex.hpp index d451ede0..6f1d3471 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_MUTEX_HPP diff --git a/node/Network.cpp b/node/Network.cpp index b7f25f7f..ee0f8611 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Network.hpp b/node/Network.hpp index faef0fed..cce6c41f 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORK_HPP diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index fe7393e8..9effe529 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 85c24090..7bae6a91 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORKCONFIG_HPP diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index 0634f435..63d44a46 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORKCONFIGMASTER_HPP diff --git a/node/Node.cpp b/node/Node.cpp index ccbe9411..5848d953 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Node.hpp b/node/Node.hpp index d25a619b..95587161 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NODE_HPP diff --git a/node/NonCopyable.hpp b/node/NonCopyable.hpp index 6d4daa86..25c71b1c 100644 --- a/node/NonCopyable.hpp +++ b/node/NonCopyable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NONCOPYABLE_HPP__ diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 285bfa5d..a2341ffd 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Constants.hpp" diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 0ecf113f..0c988804 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_OUTBOUNDMULTICAST_HPP diff --git a/node/Packet.cpp b/node/Packet.cpp index 8a57dd55..d60a3a34 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Packet.hpp b/node/Packet.hpp index 8ad2c0f9..1de679e7 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_N_PACKET_HPP diff --git a/node/Path.cpp b/node/Path.cpp index 7366b56f..a5fe1aa7 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Path.hpp" diff --git a/node/Path.hpp b/node/Path.hpp index aef628d4..32bceae0 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_PATH_HPP diff --git a/node/Peer.cpp b/node/Peer.cpp index 2e9f6a2b..01905833 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "../version.h" diff --git a/node/Peer.hpp b/node/Peer.hpp index b9d85404..9b57f23e 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_PEER_HPP diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 62d57546..ff709983 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_POLY1305_HPP diff --git a/node/Revocation.cpp b/node/Revocation.cpp index bab5653c..026058da 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Revocation.hpp" diff --git a/node/Revocation.hpp b/node/Revocation.hpp index e5e013bd..e8f5d00d 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_REVOCATION_HPP diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 7ba1c989..d8e1d699 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_RUNTIMEENVIRONMENT_HPP diff --git a/node/SHA512.cpp b/node/SHA512.cpp index 76737d37..c8d81dd1 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -1,20 +1,11 @@ +// Code taken from NaCl by D. J. Bernstein and others +// Public domain + /* - * 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 . - */ +20080913 +D. J. Bernstein +Public domain. +*/ #include #include @@ -25,18 +16,6 @@ namespace ZeroTier { -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Code taken from NaCl by D. J. Bernstein and others -// Public domain - -/* -20080913 -D. J. Bernstein -Public domain. -*/ - #define uint64 uint64_t #ifdef ZT_NO_TYPE_PUNNING diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 639a7dfd..584f8e11 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SHA512_HPP diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index cba84cdc..c5daddc3 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index c1db0c84..63c416bf 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SELFAWARENESS_HPP diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index 1dd3b43d..09010f67 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SHAREDPTR_HPP diff --git a/node/Switch.cpp b/node/Switch.cpp index 56299a9a..211b706a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Switch.hpp b/node/Switch.hpp index ff350934..9793dd45 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_N_SWITCH_HPP diff --git a/node/Tag.cpp b/node/Tag.cpp index 3f924da1..39b17f2a 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Tag.hpp" diff --git a/node/Tag.hpp b/node/Tag.hpp index 1f7f6835..746ade26 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_TAG_HPP diff --git a/node/Topology.cpp b/node/Topology.cpp index a1d37332..80f4ed4e 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "Constants.hpp" diff --git a/node/Topology.hpp b/node/Topology.hpp index d29c424e..d06ba94b 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_TOPOLOGY_HPP diff --git a/node/Utils.cpp b/node/Utils.cpp index 9ce1bf05..d69e5335 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/node/Utils.hpp b/node/Utils.hpp index ceb29d7e..25a90055 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_UTILS_HPP diff --git a/node/World.hpp b/node/World.hpp index 6e835bec..003d70e3 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_WORLD_HPP diff --git a/one.cpp b/one.cpp index b40e28fc..1f38361f 100644 --- a/one.cpp +++ b/one.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index fcc122f0..c06f459b 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp index 5f0d199a..e26fcdb3 100644 --- a/osdep/Arp.hpp +++ b/osdep/Arp.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ARP_HPP diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index 62fabc48..87a9aece 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index 8c6314db..3cb9c10e 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BSDETHERNETTAP_HPP diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index 9829f170..ee832825 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BINDER_HPP diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp index 6172f4da..34abcb67 100644 --- a/osdep/BlockingQueue.hpp +++ b/osdep/BlockingQueue.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_BLOCKINGQUEUE_HPP diff --git a/osdep/Http.cpp b/osdep/Http.cpp index 064ccd0c..d2540071 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/Http.hpp b/osdep/Http.hpp index e7d4d03e..3f98d760 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_HTTP_HPP diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index f74efc0a..2d3891e3 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index a2a00a79..ab9d2370 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_LINUXETHERNETTAP_HPP diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 3a020d61..fca1c290 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "../node/Constants.hpp" diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index fd77a79a..849bddf5 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -1,3 +1,29 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + #ifndef ZT_MANAGEDROUTE_HPP #define ZT_MANAGEDROUTE_HPP diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp index 4f636310..cd8b9b91 100644 --- a/osdep/NeighborDiscovery.cpp +++ b/osdep/NeighborDiscovery.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include "NeighborDiscovery.hpp" diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp index 47831bda..2e7a68ba 100644 --- a/osdep/NeighborDiscovery.hpp +++ b/osdep/NeighborDiscovery.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NEIGHBORDISCOVERY_HPP diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index fd5efed0..b7fce982 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index b84d5d2d..4b9ee893 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_OSUTILS_HPP diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp index f70908b8..53c9ba98 100644 --- a/osdep/OSXEthernetTap.cpp +++ b/osdep/OSXEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp index 5a96c210..ed7f39c3 100644 --- a/osdep/OSXEthernetTap.hpp +++ b/osdep/OSXEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_OSXETHERNETTAP_HPP diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index eab8a317..01a339e9 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_PHY_HPP diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index d3a19384..99286172 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_USE_MINIUPNPC diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp index 0b8d15fc..61015a09 100644 --- a/osdep/PortMapper.hpp +++ b/osdep/PortMapper.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_USE_MINIUPNPC diff --git a/osdep/TestEthernetTap.hpp b/osdep/TestEthernetTap.hpp index 6c044a94..afd89541 100644 --- a/osdep/TestEthernetTap.hpp +++ b/osdep/TestEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_TESTETHERNETTAP_HPP diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index 5423a8ab..a2f0919f 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_THREAD_HPP diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 79b9d35e..c37c7410 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index f2cf73f3..a3c1c0c3 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_WINDOWSETHERNETTAP_HPP diff --git a/selftest.cpp b/selftest.cpp index e23afd6e..209fe203 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/service/ClusterDefinition.hpp b/service/ClusterDefinition.hpp index dda1a8c8..9947e46b 100644 --- a/service/ClusterDefinition.hpp +++ b/service/ClusterDefinition.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CLUSTERDEFINITION_HPP diff --git a/service/ClusterGeoIpService.cpp b/service/ClusterGeoIpService.cpp index 89015c51..2dcc9179 100644 --- a/service/ClusterGeoIpService.cpp +++ b/service/ClusterGeoIpService.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifdef ZT_ENABLE_CLUSTER diff --git a/service/ClusterGeoIpService.hpp b/service/ClusterGeoIpService.hpp index ff2fcdb8..380f944f 100644 --- a/service/ClusterGeoIpService.hpp +++ b/service/ClusterGeoIpService.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_CLUSTERGEOIPSERVICE_HPP diff --git a/service/OneService.cpp b/service/OneService.cpp index 988e723d..9f9cec0a 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/service/OneService.hpp b/service/OneService.hpp index 3390f2ac..f52cd40e 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_ONESERVICE_HPP diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 7ec377cc..d94beab5 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #include diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index 4bb0ef51..ff3e36df 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_SOFTWAREUPDATER_HPP diff --git a/version.h b/version.h index c51bfee2..b3b2fc81 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2017 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef _ZT_VERSION_H -- cgit v1.2.3 From 02d18af57d7d05d26e44ff2015f5bcf55ebce7a2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 23 Jun 2017 16:10:26 -0700 Subject: Remove Cluster.hpp --- node/IncomingPacket.cpp | 1 - node/Network.cpp | 1 - node/Node.cpp | 1 - node/Peer.cpp | 1 - node/Switch.cpp | 1 - 5 files changed, 5 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9140c502..1d55c9f3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,7 +42,6 @@ #include "Salsa20.hpp" #include "SHA512.hpp" #include "World.hpp" -#include "Cluster.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" #include "CertificateOfRepresentation.hpp" diff --git a/node/Network.cpp b/node/Network.cpp index 74d81941..12deeeb7 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -42,7 +42,6 @@ #include "NetworkController.hpp" #include "Node.hpp" #include "Peer.hpp" -#include "Cluster.hpp" // Uncomment to make the rules engine dump trace info to stdout //#define ZT_RULES_ENGINE_DEBUGGING 1 diff --git a/node/Node.cpp b/node/Node.cpp index 37586834..39325b65 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -45,7 +45,6 @@ #include "Address.hpp" #include "Identity.hpp" #include "SelfAwareness.hpp" -#include "Cluster.hpp" #include "Network.hpp" const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; diff --git a/node/Peer.cpp b/node/Peer.cpp index 01905833..84086048 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -32,7 +32,6 @@ #include "Switch.hpp" #include "Network.hpp" #include "SelfAwareness.hpp" -#include "Cluster.hpp" #include "Packet.hpp" namespace ZeroTier { diff --git a/node/Switch.cpp b/node/Switch.cpp index 211b706a..2be54b37 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -43,7 +43,6 @@ #include "Peer.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" -#include "Cluster.hpp" namespace ZeroTier { -- cgit v1.2.3 From baa10c2995b7e0e49b49fe63a264a20982b817cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 30 Jun 2017 17:32:07 -0700 Subject: . --- include/ZeroTierOne.h | 8 +-- node/Constants.hpp | 2 +- node/IncomingPacket.cpp | 8 +-- node/Network.cpp | 14 +++-- node/Node.cpp | 24 ++++--- node/Node.hpp | 6 +- node/Path.hpp | 30 +++++++++ node/Peer.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++------ node/Peer.hpp | 54 ++++++---------- node/Topology.cpp | 32 +++++++--- node/Topology.hpp | 2 +- service/OneService.cpp | 130 +++++++++++++++++++++----------------- 12 files changed, 326 insertions(+), 148 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 9c295cee..40cae3b4 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1115,14 +1115,14 @@ enum ZT_StateObjectType * Canonical path: /peers.d/
(10-digit hex address) * Persistence: optional, can be purged at any time */ - ZT_STATE_OBJECT_PEER = 3, + ZT_STATE_OBJECT_PEER_STATE = 3, /** * The identity of a known peer * * Object ID: peer address * Canonical path: /iddb.d/
(10-digit hex address) - * Persistence: optional, can be purged at any time, recommended ttl 30-60 days + * Persistence: recommended, can be purged at any time, recommended ttl 30-60 days */ ZT_STATE_OBJECT_PEER_IDENTITY = 4, @@ -1248,7 +1248,7 @@ typedef void (*ZT_StatePutFunction)( void *, /* User ptr */ void *, /* Thread ptr */ enum ZT_StateObjectType, /* State object type */ - uint64_t, /* State object ID (if applicable) */ + const uint64_t [2], /* State object ID (if applicable) */ const void *, /* State object data */ int); /* Length of data or -1 to delete */ @@ -1264,7 +1264,7 @@ typedef int (*ZT_StateGetFunction)( void *, /* User ptr */ void *, /* Thread ptr */ enum ZT_StateObjectType, /* State object type */ - uint64_t, /* State object ID (if applicable) */ + const uint64_t [2], /* State object ID (if applicable) */ void *, /* Buffer to store state object data */ unsigned int); /* Length of data buffer in bytes */ diff --git a/node/Constants.hpp b/node/Constants.hpp index fbbba76e..88549937 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -216,7 +216,7 @@ /** * How often Topology::clean() and Network::clean() and similar are called, in ms */ -#define ZT_HOUSEKEEPING_PERIOD 120000 +#define ZT_HOUSEKEEPING_PERIOD 10000 /** * How long to remember peer records in RAM if they haven't been used diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 1d55c9f3..4d99e87d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1211,8 +1211,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - peer->setClusterPreferred(a); + //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + // peer->setClusterPreferred(a); if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); @@ -1228,8 +1228,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - peer->setClusterPreferred(a); + //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) + // peer->setClusterPreferred(a); if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); diff --git a/node/Network.cpp b/node/Network.cpp index 8c6f2ce8..0a16ded8 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -700,10 +700,13 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u this->setConfiguration(tPtr,*nconf,false); _lastConfigUpdate = 0; // still want to re-request since it's likely outdated } else { + uint64_t tmp[2]; + tmp[0] = nwid; tmp[1] = 0; + bool got = false; Dictionary *dict = new Dictionary(); try { - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,nwid,dict->unsafeData(),ZT_NETWORKCONFIG_DICT_CAPACITY - 1); + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,dict->unsafeData(),ZT_NETWORKCONFIG_DICT_CAPACITY - 1); if (n > 1) { NetworkConfig *nconf = new NetworkConfig(); try { @@ -719,7 +722,7 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u delete dict; if (!got) - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,nwid,"\n",1); + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1); } if (!_portInitialized) { @@ -1185,8 +1188,11 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD if (saveToDisk) { Dictionary *d = new Dictionary(); try { - if (nconf.toDictionary(*d,false)) - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,_id,d->data(),d->sizeBytes()); + if (nconf.toDictionary(*d,false)) { + uint64_t tmp[2]; + tmp[0] = _id; tmp[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d->data(),d->sizeBytes()); + } } catch ( ... ) {} delete d; } diff --git a/node/Node.cpp b/node/Node.cpp index ab49e63b..1112c0f2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -76,22 +76,26 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); + uint64_t idtmp[2]; + idtmp[0] = 0; idtmp[1] = 0; char tmp[512]; std::string tmp2; - int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,0,tmp,sizeof(tmp) - 1); + int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; if (!RR->identity.fromString(tmp)) n = -1; } + + idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; if (n <= 0) { RR->identity.generate(); tmp2 = RR->identity.toString(true); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,RR->identity.address().toInt(),tmp2.data(),(unsigned int)tmp2.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp2.data(),(unsigned int)tmp2.length()); tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,RR->identity.address().toInt(),tmp2.data(),(unsigned int)tmp2.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); } else { - n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,RR->identity.address().toInt(),tmp,sizeof(tmp) - 1); + n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; if (RR->identity.toString(false) != tmp) @@ -99,7 +103,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } if (n <= 0) { tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,RR->identity.address().toInt(),tmp2.data(),(unsigned int)tmp2.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); } } @@ -145,7 +149,7 @@ ZT_ResultCode Node::processStateUpdate( ZT_ResultCode r = ZT_RESULT_OK_IGNORED; switch(type) { - case ZT_STATE_OBJECT_PEER: + case ZT_STATE_OBJECT_PEER_STATE: if (len) { } break; @@ -380,9 +384,9 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { + _lastHousekeepingRun = now; try { - _lastHousekeepingRun = now; - RR->topology->clean(now); + RR->topology->doPeriodicTasks(tptr,now); RR->sa->clean(now); RR->mc->clean(now); } catch ( ... ) { @@ -443,7 +447,9 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr) _networks.erase(nwid); } - RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,nwid); + uint64_t tmp[2]; + tmp[0] = nwid; tmp[1] = 0; + RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp); return ZT_RESULT_OK; } diff --git a/node/Node.hpp b/node/Node.hpp index f407c60c..f1209d00 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -197,9 +197,9 @@ public: inline bool online() const throw() { return _online; } - inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id,void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,maxlen); } - inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id,const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,(int)len); } - inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,(const void *)0,-1); } + inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,maxlen); } + inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,(int)len); } + inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,(const void *)0,-1); } #ifdef ZT_TRACE void postTrace(const char *module,unsigned int line,const char *fmt,...); diff --git a/node/Path.hpp b/node/Path.hpp index 32bceae0..74b31d8d 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -46,6 +46,11 @@ */ #define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1) +/** + * Maximum distance for a path + */ +#define ZT_PATH_DISTANCE_MAX 0xffff + namespace ZeroTier { class RuntimeEnvironment; @@ -120,6 +125,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _distance(ZT_PATH_DISTANCE_MAX), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -137,6 +143,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _distance(ZT_PATH_DISTANCE_MAX), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -299,6 +306,28 @@ public: */ inline uint64_t lastIn() const { return _lastIn; } + /** + * @return Time last trust-established packet was received + */ + inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } + + /** + * @return Distance (higher is further) + */ + inline unsigned int distance() const { return _distance; } + + /** + * @param lo Last out send + * @param li Last in send + * @param lt Last trust established packet received + */ + inline void updateFromRemoteState(const uint64_t lo,const uint64_t li,const uint64_t lt) + { + _lastOut = lo; + _lastIn = li; + _lastTrustEstablishedPacketReceived = lt; + } + /** * Return and increment outgoing packet counter (used with Packet::armor()) * @@ -315,6 +344,7 @@ private: volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; + volatile unsigned int _distance; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index 84086048..a7466296 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -38,6 +38,8 @@ namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : RR(renv), + _lastWroteState(0), + _lastReceivedStateTimestamp(0), _lastReceive(0), _lastNontrivialReceive(0), _lastTriedMemorizedPath(0), @@ -75,6 +77,7 @@ void Peer::received( { const uint64_t now = RR->node->now(); +/* #ifdef ZT_ENABLE_CLUSTER bool isClusterSuboptimalPath = false; if ((RR->cluster)&&(hops == 0)) { @@ -120,6 +123,7 @@ void Peer::received( } } #endif +*/ _lastReceive = now; switch (verb) { @@ -143,6 +147,8 @@ void Peer::received( if (hops == 0) { bool pathAlreadyKnown = false; + bool newPathLearned = false; + { Mutex::Lock _l(_paths_m); if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { @@ -152,9 +158,6 @@ void Peer::received( const struct sockaddr_in *const ll = reinterpret_cast(&(_v4Path.p->localAddress())); if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { _v4Path.lr = now; -#ifdef ZT_ENABLE_CLUSTER - _v4Path.localClusterSuboptimal = isClusterSuboptimalPath; -#endif pathAlreadyKnown = true; } } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { @@ -164,9 +167,6 @@ void Peer::received( const struct sockaddr_in6 *const ll = reinterpret_cast(&(_v6Path.p->localAddress())); if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { _v6Path.lr = now; -#ifdef ZT_ENABLE_CLUSTER - _v6Path.localClusterSuboptimal = isClusterSuboptimalPath; -#endif pathAlreadyKnown = true; } } @@ -176,11 +176,11 @@ void Peer::received( Mutex::Lock _l(_paths_m); _PeerPath *potentialNewPeerPath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { - if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) { + if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) { potentialNewPeerPath = &_v4Path; } } else if (path->address().ss_family == AF_INET6) { - if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) { + if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) { potentialNewPeerPath = &_v6Path; } } @@ -188,11 +188,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { potentialNewPeerPath->lr = now; potentialNewPeerPath->p = path; -#ifdef ZT_ENABLE_CLUSTER - potentialNewPeerPath->localClusterSuboptimal = isClusterSuboptimalPath; - if (RR->cluster) - RR->cluster->broadcastHavePeer(_id); -#endif + newPathLearned = true; } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -200,15 +196,12 @@ void Peer::received( } } } + + if (newPathLearned) + writeState(tPtr,now); } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) -#ifdef ZT_ENABLE_CLUSTER - // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection - const bool haveCluster = (RR->cluster); -#else - const bool haveCluster = false; -#endif - if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) { + if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; std::vector pathsToPush; @@ -439,4 +432,135 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } +void Peer::writeState(void *tPtr,const uint64_t now) +{ + try { + Buffer b; + + b.append((uint8_t)1); // version + b.append(now); + + _id.serialize(b); + + { + Mutex::Lock _l(_paths_m); + unsigned int count = 0; + if (_v4Path.lr) + ++count; + if (_v6Path.lr) + ++count; + b.append((uint8_t)count); + if (_v4Path.lr) { + b.append(_v4Path.lr); + b.append(_v4Path.p->lastOut()); + b.append(_v4Path.p->lastIn()); + b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); + b.append((uint16_t)_v4Path.p->distance()); + _v4Path.p->address().serialize(b); + _v4Path.p->localAddress().serialize(b); + } + if (_v6Path.lr) { + b.append(_v6Path.lr); + b.append(_v6Path.p->lastOut()); + b.append(_v6Path.p->lastIn()); + b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); + b.append((uint16_t)_v6Path.p->distance()); + _v6Path.p->address().serialize(b); + _v6Path.p->localAddress().serialize(b); + } + } + + b.append(_lastReceive); + b.append(_lastNontrivialReceive); + b.append(_lastTriedMemorizedPath); + b.append(_lastDirectPathPushSent); + b.append(_lastDirectPathPushReceive); + b.append(_lastCredentialRequestSent); + b.append(_lastWhoisRequestReceived); + b.append(_lastEchoRequestReceived); + b.append(_lastComRequestReceived); + b.append(_lastComRequestSent); + b.append(_lastCredentialsReceived); + b.append(_lastTrustEstablishedPacketReceived); + + b.append(_vProto); + b.append(_vMajor); + b.append(_vMinor); + b.append(_vRevision); + + b.append((uint16_t)0); // length of additional fields + + uint64_t tmp[2]; + tmp[0] = _id.address().toInt(); tmp[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); + + _lastWroteState = now; + } catch ( ... ) {} // sanity check, should not be possible +} + +bool Peer::applyStateUpdate(const void *data,unsigned int len) +{ + try { + Buffer b(data,len); + unsigned int ptr = 0; + + if (b[ptr++] != 1) + return false; + const uint64_t ts = b.at(ptr); ptr += 8; + if (ts <= _lastReceivedStateTimestamp) + return false; + + const unsigned int pathCount = (unsigned int)b[ptr++]; + { + Mutex::Lock _l(_paths_m); + for(unsigned int i=0;i(ptr); ptr += 8; + const uint64_t lastOut = b.at(ptr); ptr += 8; + const uint64_t lastIn = b.at(ptr); ptr += 8; + const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; + const unsigned int distance = b.at(ptr); ptr += 2; + InetAddress addr,localAddr; + ptr += addr.deserialize(b,ptr); + ptr += localAddr.deserialize(b,ptr); + if (addr.ss_family == localAddr.ss_family) { + _PeerPath *p = (_PeerPath *)0; + switch(addr.ss_family) { + case AF_INET: p = &_v4Path; break; + case AF_INET6: p = &_v6Path; break; + } + if (p) { + if ( ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) && (p->p->distance() > distance) ) + p->p = RR->topology->getPath(localAddr,addr); + p->lr = lr; + p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); + } + } + } + } + + _lastReceive = std::max(_lastReceive,b.at(ptr)); ptr += 8; + _lastNontrivialReceive = std::max(_lastNontrivialReceive,b.at(ptr)); ptr += 8; + _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,b.at(ptr)); ptr += 8; + _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,b.at(ptr)); ptr += 8; + _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,b.at(ptr)); ptr += 8; + _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,b.at(ptr)); ptr += 8; + _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,b.at(ptr)); ptr += 8; + _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,b.at(ptr)); ptr += 8; + _lastComRequestReceived = std::max(_lastComRequestReceived,b.at(ptr)); ptr += 8; + _lastComRequestSent = std::max(_lastComRequestSent,b.at(ptr)); ptr += 8; + _lastCredentialsReceived = std::max(_lastCredentialsReceived,b.at(ptr)); ptr += 8; + _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,b.at(ptr)); ptr += 8; + + _vProto = b.at(ptr); ptr += 2; + _vMajor = b.at(ptr); ptr += 2; + _vMinor = b.at(ptr); ptr += 2; + _vRevision = b.at(ptr); ptr += 2; + + _lastReceivedStateTimestamp = ts; + + return true; + } catch ( ... ) {} // ignore invalid state updates + return false; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 9b57f23e..d6b7dad9 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -193,6 +193,22 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); + /** + * Write current peer state to external storage / cluster network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + void writeState(void *tPtr,const uint64_t now); + + /** + * Apply a state update received from e.g. a remote cluster member + * + * @param data State update data + * @param len Length of state update + * @return True if state update was applied, false if ignored or invalid + */ + bool applyStateUpdate(const void *data,unsigned int len); + /** * Reset paths within a given IP scope and address family * @@ -218,19 +234,6 @@ public: } } - /** - * Indicate that the given address was provided by a cluster as a preferred destination - * - * @param addr Address cluster prefers that we use - */ - inline void setClusterPreferred(const InetAddress &addr) - { - if (addr.ss_family == AF_INET) - _v4ClusterPreferred = addr; - else if (addr.ss_family == AF_INET6) - _v6ClusterPreferred = addr; - } - /** * Fill parameters with V4 and V6 addresses if known and alive * @@ -317,18 +320,6 @@ public: else _latency = std::min(l,(unsigned int)65535); } -#ifdef ZT_ENABLE_CLUSTER - /** - * @param now Current time - * @return True if this peer has at least one active direct path that is not cluster-suboptimal - */ - inline bool hasLocalClusterOptimalPath(uint64_t now) const - { - Mutex::Lock _l(_paths_m); - return ( ((_v4Path.p)&&(_v4Path.p->alive(now))&&(!_v4Path.localClusterSuboptimal)) || ((_v6Path.p)&&(_v6Path.p->alive(now))&&(!_v6Path.localClusterSuboptimal)) ); - } -#endif - /** * @return 256-bit secret symmetric encryption key */ @@ -449,22 +440,18 @@ public: private: struct _PeerPath { -#ifdef ZT_ENABLE_CLUSTER - _PeerPath() : lr(0),p(),localClusterSuboptimal(false) {} -#else _PeerPath() : lr(0),p() {} -#endif uint64_t lr; // time of last valid ZeroTier packet SharedPtr p; -#ifdef ZT_ENABLE_CLUSTER - bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer -#endif }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; const RuntimeEnvironment *RR; + uint64_t _lastWroteState; + uint64_t _lastReceivedStateTimestamp; + uint64_t _lastReceive; // direct or indirect uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. uint64_t _lastTriedMemorizedPath; @@ -483,9 +470,6 @@ private: uint16_t _vMinor; uint16_t _vRevision; - InetAddress _v4ClusterPreferred; - InetAddress _v6ClusterPreferred; - _PeerPath _v4Path; // IPv4 direct path _PeerPath _v6Path; // IPv6 direct path Mutex _paths_m; diff --git a/node/Topology.cpp b/node/Topology.cpp index d4b424ff..be116b28 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -69,7 +69,9 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : _amRoot(false) { uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,0,tmp,sizeof(tmp)); + uint64_t idtmp[2]; + idtmp[0] = 0; idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp)); if (n > 0) { try { World cachedPlanet; @@ -159,7 +161,9 @@ void Topology::saveIdentity(void *tPtr,const Identity &id) { if (id) { const std::string tmp(id.toString(false)); - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,id.address().toInt(),tmp.data(),(unsigned int)tmp.length()); + uint64_t idtmp[2]; + idtmp[0] = id.address().toInt(); idtmp[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp.data(),(unsigned int)tmp.length()); } } @@ -329,7 +333,9 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) try { Buffer sbuf; existing->serialize(sbuf,false); - RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,existing->id(),sbuf.data(),sbuf.size()); + uint64_t idtmp[2]; + idtmp[0] = existing->id(); idtmp[1] = 0; + RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size()); } catch ( ... ) {} _memoizeUpstreams(tPtr); @@ -340,7 +346,9 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) { char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,id,tmp,sizeof(tmp)); + uint64_t idtmp[2]; + idtmp[0] = id; idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp)); if (n > 0) { try { World w; @@ -369,7 +377,9 @@ void Topology::removeMoon(void *tPtr,const uint64_t id) if (m->id() != id) { nm.push_back(*m); } else { - RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,id); + uint64_t idtmp[2]; + idtmp[0] = id; idtmp[1] = 0; + RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp); } } _moons.swap(nm); @@ -384,7 +394,7 @@ void Topology::removeMoon(void *tPtr,const uint64_t id) _memoizeUpstreams(tPtr); } -void Topology::clean(uint64_t now) +void Topology::doPeriodicTasks(void *tPtr,uint64_t now) { { Mutex::Lock _l1(_peers_m); @@ -393,10 +403,14 @@ void Topology::clean(uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { _peers.erase(*a); + } else { + (*p)->writeState(tPtr,now); + } } } + { Mutex::Lock _l(_paths_m); Hashtable< Path::HashKey,SharedPtr >::Iterator i(_paths); @@ -412,7 +426,9 @@ void Topology::clean(uint64_t now) Identity Topology::_getIdentity(void *tPtr,const Address &zta) { char tmp[512]; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,zta.toInt(),tmp,sizeof(tmp) - 1); + uint64_t idtmp[2]; + idtmp[0] = zta.toInt(); idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; try { diff --git a/node/Topology.hpp b/node/Topology.hpp index d06ba94b..9bc7c0d8 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -308,7 +308,7 @@ public: /** * Clean and flush database */ - void clean(uint64_t now); + void doPeriodicTasks(void *tPtr,uint64_t now); /** * @param now Current time diff --git a/service/OneService.cpp b/service/OneService.cpp index 993fb116..f949f348 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -312,8 +312,8 @@ class OneServiceImpl; static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); -static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,const void *data,int len); -static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,void *data,unsigned int maxlen); +static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len); +static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen); static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); @@ -1220,34 +1220,20 @@ public: res["planetWorldId"] = planet.id(); res["planetWorldTimestamp"] = planet.timestamp(); -/* -#ifdef ZT_ENABLE_CLUSTER - json cj; - ZT_ClusterStatus cs; - _node->clusterStatus(&cs); - if (cs.clusterSize >= 1) { - json cja = json::array(); - for(unsigned int i=0;i::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) { + uint64_t up = 0; + for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { + if (((*c)->remoteAddr == *ca)&&((*c)->clusterMemberId)&&((*c)->lastReceive > up)) + up = (*c)->lastReceive; + } + cj[ca->toString()] = up; } - cj["members"] = cja; - cj["myId"] = (int)cs.myId; - cj["clusterSize"] = cs.clusterSize; + res["cluster"] = cj; } - res["cluster"] = cj; -#else - res["cluster"] = json(); -#endif -*/ scode = 200; } else if (ps[0] == "moon") { @@ -1877,16 +1863,15 @@ public: return false; } - void replicateStateObject(const ZT_StateObjectType type,const uint64_t id,const void *const data,const unsigned int len,TcpConnection *tc) + void replicateStateObject(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,TcpConnection *tc) { - char buf[34]; - + char buf[42]; Mutex::Lock _l2(tc->writeq_m); if (tc->writeq.length() == 0) _phy.setNotifyWritable(tc->sock,true); - const unsigned int mlen = len + 34; + const unsigned int mlen = len + 42; tc->writeq.push_back((char)((mlen >> 16) & 0xff)); tc->writeq.push_back((char)((mlen >> 8) & 0xff)); @@ -1895,24 +1880,32 @@ public: Utils::getSecureRandom(buf,16); buf[24] = (char)CLUSTER_MESSAGE_STATE_OBJECT; buf[25] = (char)type; - buf[26] = (char)((id >> 56) & 0xff); - buf[27] = (char)((id >> 48) & 0xff); - buf[28] = (char)((id >> 40) & 0xff); - buf[29] = (char)((id >> 32) & 0xff); - buf[30] = (char)((id >> 24) & 0xff); - buf[31] = (char)((id >> 16) & 0xff); - buf[32] = (char)((id >> 8) & 0xff); - buf[33] = (char)(id & 0xff); + buf[26] = (char)((id[0] >> 56) & 0xff); + buf[27] = (char)((id[0] >> 48) & 0xff); + buf[28] = (char)((id[0] >> 40) & 0xff); + buf[29] = (char)((id[0] >> 32) & 0xff); + buf[30] = (char)((id[0] >> 24) & 0xff); + buf[31] = (char)((id[0] >> 16) & 0xff); + buf[32] = (char)((id[0] >> 8) & 0xff); + buf[33] = (char)(id[0] & 0xff); + buf[34] = (char)((id[1] >> 56) & 0xff); + buf[35] = (char)((id[1] >> 48) & 0xff); + buf[36] = (char)((id[1] >> 40) & 0xff); + buf[37] = (char)((id[1] >> 32) & 0xff); + buf[38] = (char)((id[1] >> 24) & 0xff); + buf[39] = (char)((id[1] >> 16) & 0xff); + buf[40] = (char)((id[1] >> 8) & 0xff); + buf[41] = (char)(id[1] & 0xff); const unsigned long startpos = (unsigned long)tc->writeq.length(); - tc->writeq.append(buf,34); + tc->writeq.append(buf,42); tc->writeq.append(reinterpret_cast(data),len); char *const outdata = const_cast(tc->writeq.data()) + startpos; encryptClusterMessage(outdata,mlen); } - void replicateStateObjectToCluster(const ZT_StateObjectType type,const uint64_t id,const void *const data,const unsigned int len,const uint64_t everyoneBut) + void replicateStateObjectToCluster(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,const uint64_t everyoneBut) { std::vector sentTo; if (everyoneBut) @@ -1927,7 +1920,7 @@ public: } } - void writeStateObject(enum ZT_StateObjectType type,uint64_t id,const void *data,int len) + void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { char p[4096]; bool secure = false; @@ -1940,17 +1933,17 @@ public: secure = true; break; case ZT_STATE_OBJECT_PEER_IDENTITY: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id); + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id[0]); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); secure = true; break; case ZT_STATE_OBJECT_PLANET: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id); + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); break; default: p[0] = (char)0; @@ -1985,8 +1978,12 @@ public: if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { if (f->length() == 21) { const uint64_t nwid = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (nwid) - replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,nwid,buf.data(),(int)buf.length(),tc); + if (nwid) { + uint64_t tmp[2]; + tmp[0] = nwid; + tmp[1] = 0; + replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,buf.data(),(int)buf.length(),tc); + } } } } @@ -1996,8 +1993,12 @@ public: if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { if (f->length() == 21) { const uint64_t moonId = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (moonId) - replicateStateObject(ZT_STATE_OBJECT_MOON,moonId,buf.data(),(int)buf.length(),tc); + if (moonId) { + uint64_t tmp[2]; + tmp[0] = moonId; + tmp[1] = 0; + replicateStateObject(ZT_STATE_OBJECT_MOON,tmp,buf.data(),(int)buf.length(),tc); + } } } } @@ -2313,8 +2314,9 @@ public: break; case CLUSTER_MESSAGE_STATE_OBJECT: - if (mlen >= (25 + 9)) { // type + object ID + [data] - const uint64_t objId = ( + if (mlen >= 42) { // type + object ID + [data] + uint64_t objId[2]; + objId[0] = ( ((uint64_t)data[26] << 56) | ((uint64_t)data[27] << 48) | ((uint64_t)data[28] << 40) | @@ -2324,9 +2326,19 @@ public: ((uint64_t)data[32] << 8) | (uint64_t)data[33] ); - if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 34,(unsigned int)(mlen - 34)) == ZT_RESULT_OK) { - writeStateObject((ZT_StateObjectType)data[25],objId,data + 34,(unsigned int)(mlen - 34)); - replicateStateObjectToCluster((ZT_StateObjectType)data[25],objId,data + 34,(unsigned int)(mlen - 34),tc->clusterMemberId); + objId[1] = ( + ((uint64_t)data[34] << 56) | + ((uint64_t)data[35] << 48) | + ((uint64_t)data[36] << 40) | + ((uint64_t)data[37] << 32) | + ((uint64_t)data[38] << 24) | + ((uint64_t)data[39] << 16) | + ((uint64_t)data[40] << 8) | + (uint64_t)data[41] + ); + if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId[0],data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) { + writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)); + replicateStateObjectToCluster((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42),tc->clusterMemberId); } } break; @@ -2543,13 +2555,13 @@ public: } } - inline void nodeStatePutFunction(enum ZT_StateObjectType type,uint64_t id,const void *data,int len) + inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { writeStateObject(type,id,data,len); replicateStateObjectToCluster(type,id,data,len,0); } - inline int nodeStateGetFunction(enum ZT_StateObjectType type,uint64_t id,void *data,unsigned int maxlen) + inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { char p[4096]; switch(type) { @@ -2866,9 +2878,9 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr { return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) { reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } -static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,const void *data,int len) +static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { reinterpret_cast(uptr)->nodeStatePutFunction(type,id,data,len); } -static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,uint64_t id,void *data,unsigned int maxlen) +static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { return reinterpret_cast(uptr)->nodeStateGetFunction(type,id,data,maxlen); } static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } -- cgit v1.2.3 From 2f20258807f8665bc3f9c527106e61761e01ecc3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 10:25:36 -0700 Subject: . --- include/ZeroTierOne.h | 34 +++++----- node/Constants.hpp | 12 ++-- node/Identity.hpp | 5 +- node/IncomingPacket.cpp | 12 ---- node/Network.cpp | 10 --- node/Node.cpp | 151 +++++++++++--------------------------------- node/Node.hpp | 2 +- node/Path.hpp | 13 ---- node/Peer.cpp | 113 ++++++++++++++++++++------------- node/Peer.hpp | 16 ++++- node/RuntimeEnvironment.hpp | 19 ++++-- node/Switch.cpp | 93 ++------------------------- node/Topology.cpp | 59 +++++------------ node/Topology.hpp | 27 ++------ osdep/Binder.hpp | 4 +- service/OneService.cpp | 94 +++++++++++++-------------- 16 files changed, 240 insertions(+), 424 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 40cae3b4..133ae340 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1072,9 +1072,9 @@ typedef struct * identity of a node and its address, the identity (public and secret) * must be saved at a minimum. * - * The reference service implementation currently persists identity, - * peer identities (for a period of time), planet, moons, and network - * configurations. Other state is treated as ephemeral. + * State objects actually have two IDs (uint64_t[2]). If only one is + * listed the second ([1]) should be zero and is ignored in storage + * and replication. * * All state objects should be replicated in cluster mode. The reference * clustering implementation uses a rumor mill algorithm in which state @@ -1118,22 +1118,25 @@ enum ZT_StateObjectType ZT_STATE_OBJECT_PEER_STATE = 3, /** - * The identity of a known peer + * Network configuration * * Object ID: peer address - * Canonical path: /iddb.d/
(10-digit hex address) - * Persistence: recommended, can be purged at any time, recommended ttl 30-60 days + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist */ - ZT_STATE_OBJECT_PEER_IDENTITY = 4, + ZT_STATE_OBJECT_NETWORK_CONFIG = 4, /** - * Network configuration + * Network membership (network X peer intersection) * - * Object ID: peer address - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist + * If these are persisted they must be restored after peer states and + * network configs. Otherwise they are ignored. + * + * Object ID: [0] network ID, [1] peer address + * Canonical path: /networks.d//members.d/
+ * Persistence: optional (not usually needed) */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 5, + ZT_STATE_OBJECT_NETWORK_MEMBERSHIP = 5, /** * The planet (there is only one per... well... planet!) @@ -1450,7 +1453,8 @@ void ZT_Node_delete(ZT_Node *node); * * Unless clustering is being implemented this function doesn't need to be * used after startup. It could be called in response to filesystem changes - * to allow some degree of live configurability by filesystem observation. + * to allow some degree of live configurability by filesystem observation + * but this kind of thing is entirely optional. * * The return value of this function indicates whether the update was accepted * as new. A return value of ZT_RESULT_OK indicates that the node gleaned new @@ -1468,7 +1472,7 @@ void ZT_Node_delete(ZT_Node *node); * @param node Node instance * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param type State object type - * @param id State object ID + * @param id State object ID (if object type has only one ID, second should be zero) * @param data State object data * @param len Length of state object data in bytes * @return ZT_RESULT_OK if object was accepted or ZT_RESULT_OK_IGNORED if non-informative, error if object was invalid @@ -1477,7 +1481,7 @@ enum ZT_ResultCode ZT_Node_processStateUpdate( ZT_Node *node, void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len); diff --git a/node/Constants.hpp b/node/Constants.hpp index 88549937..274b9564 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -216,7 +216,12 @@ /** * How often Topology::clean() and Network::clean() and similar are called, in ms */ -#define ZT_HOUSEKEEPING_PERIOD 10000 +#define ZT_HOUSEKEEPING_PERIOD 60000 + +/** + * How often in ms to write peer state to storage and/or cluster (approximate) + */ +#define ZT_PEER_STATE_WRITE_PERIOD 10000 /** * How long to remember peer records in RAM if they haven't been used @@ -322,11 +327,6 @@ */ #define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000) -/** - * Send a full HELLO every this often (ms) - */ -#define ZT_PEER_SEND_FULL_HELLO_EVERY (ZT_PEER_PING_PERIOD * 2) - /** * How often to retry expired paths that we're still remembering */ diff --git a/node/Identity.hpp b/node/Identity.hpp index b1c7d6f4..79e17f4d 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -91,7 +91,10 @@ public: ~Identity() { - delete _privateKey; + if (_privateKey) { + Utils::burn(_privateKey,sizeof(C25519::Private)); + delete _privateKey; + } } inline Identity &operator=(const Identity &id) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 4d99e87d..0548387b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -585,12 +585,6 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar } else { // Request unknown WHOIS from upstream from us (if we have one) RR->sw->requestWhois(tPtr,addr); -#ifdef ZT_ENABLE_CLUSTER - // Distribute WHOIS queries across a cluster if we do not know the ID. - // This may result in duplicate OKs to the querying peer, which is fine. - if (RR->cluster) - RR->cluster->sendDistributedQuery(*this); -#endif } } @@ -1055,12 +1049,6 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - - // If we are a member of a cluster, distribute this GATHER across it -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(gatheredLocally < gatherLimit)) - RR->cluster->sendDistributedQuery(*this); -#endif } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); diff --git a/node/Network.cpp b/node/Network.cpp index 0a16ded8..bccc0397 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1067,11 +1067,6 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add return 0; } -#ifdef ZT_ENABLE_CLUSTER - if ((source)&&(RR->cluster)) - RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); -#endif - // New properly verified chunks can be flooded "virally" through the network if (fastPropagate) { Address *a = (Address *)0; @@ -1099,11 +1094,6 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) c = &(_incomingConfigChunks[i]); } - -#ifdef ZT_ENABLE_CLUSTER - if ((source)&&(RR->cluster)) - RR->cluster->broadcastNetworkConfigChunk(chunk.field(start,chunk.size() - start),chunk.size() - start); -#endif } else { TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); return 0; diff --git a/node/Node.cpp b/node/Node.cpp index 1112c0f2..4ffe496c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -68,6 +68,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 throw std::runtime_error("callbacks struct version mismatch"); memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); + // Initialize non-cryptographic PRNG from a good random source Utils::getSecureRandom((void *)_prngState,sizeof(_prngState)); _online = false; @@ -78,33 +79,34 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0; - char tmp[512]; - std::string tmp2; + char tmp[1024]; int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; - if (!RR->identity.fromString(tmp)) + if (RR->identity.fromString(tmp)) { + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + } else { n = -1; + } } idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; if (n <= 0) { RR->identity.generate(); - tmp2 = RR->identity.toString(true); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp2.data(),(unsigned int)tmp2.length()); - tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); + RR->publicIdentityStr = RR->identity.toString(false); + RR->secretIdentityStr = RR->identity.toString(true); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr.data(),(unsigned int)RR->secretIdentityStr.length()); + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr.data(),(unsigned int)RR->publicIdentityStr.length()); } else { n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; - if (RR->identity.toString(false) != tmp) + if (RR->publicIdentityStr != tmp) n = -1; } - if (n <= 0) { - tmp2 = RR->identity.toString(false); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp2.data(),(unsigned int)tmp2.length()); - } + if (n <= 0) + stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr.data(),(unsigned int)RR->publicIdentityStr.length()); } try { @@ -125,24 +127,20 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 Node::~Node() { - Mutex::Lock _l(_networks_m); - - _networks.clear(); // destroy all networks before shutdown - + { + Mutex::Lock _l(_networks_m); + _networks.clear(); // destroy all networks before shutdown + } delete RR->sa; delete RR->topology; delete RR->mc; delete RR->sw; - -#ifdef ZT_ENABLE_CLUSTER - delete RR->cluster; -#endif } ZT_ResultCode Node::processStateUpdate( void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len) { @@ -151,11 +149,12 @@ ZT_ResultCode Node::processStateUpdate( case ZT_STATE_OBJECT_PEER_STATE: if (len) { - } - break; - - case ZT_STATE_OBJECT_PEER_IDENTITY: - if (len) { + const SharedPtr p(RR->topology->getPeer(tptr,Address(id[0]))); + if (p) { + r = (p->applyStateUpdate(data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; + } else { + r = (Peer::createFromStateUpdate(RR,tptr,data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; + } } break; @@ -163,9 +162,9 @@ ZT_ResultCode Node::processStateUpdate( if (len <= (ZT_NETWORKCONFIG_DICT_CAPACITY - 1)) { if (len < 2) { Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id]; + SharedPtr &nw = _networks[id[0]]; if (!nw) { - nw = SharedPtr(new Network(RR,tptr,id,(void *)0,(const NetworkConfig *)0)); + nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,(const NetworkConfig *)0)); r = ZT_RESULT_OK; } } else { @@ -175,7 +174,7 @@ ZT_ResultCode Node::processStateUpdate( try { if (nconf->fromDictionary(*dict)) { Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id]; + SharedPtr &nw = _networks[id[0]]; if (nw) { switch (nw->setConfiguration(tptr,*nconf,false)) { default: @@ -189,7 +188,7 @@ ZT_ResultCode Node::processStateUpdate( break; } } else { - nw = SharedPtr(new Network(RR,tptr,id,(void *)0,nconf)); + nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,nconf)); } } else { r = ZT_RESULT_ERROR_BAD_PARAMETER; @@ -208,9 +207,14 @@ ZT_ResultCode Node::processStateUpdate( } break; + case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: + if (len) { + } + break; + case ZT_STATE_OBJECT_PLANET: case ZT_STATE_OBJECT_MOON: - if (len <= ZT_WORLD_MAX_SERIALIZED_LENGTH) { + if ((len)&&(len <= ZT_WORLD_MAX_SERIALIZED_LENGTH)) { World w; try { w.deserialize(Buffer(data,len)); @@ -395,18 +399,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } try { -#ifdef ZT_ENABLE_CLUSTER - // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior - if (RR->cluster) { - RR->sw->doTimerTasks(tptr,now); - RR->cluster->doPeriodicTasks(); - *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate - } else { -#endif - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); -#ifdef ZT_ENABLE_CLUSTER - } -#endif + *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -620,76 +613,6 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController->init(RR->identity,this); } -/* -ZT_ResultCode Node::clusterInit( - unsigned int myId, - const struct sockaddr_storage *zeroTierPhysicalEndpoints, - unsigned int numZeroTierPhysicalEndpoints, - int x, - int y, - int z, - void (*sendFunction)(void *,unsigned int,const void *,unsigned int), - void *sendFunctionArg, - int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *), - void *addressToLocationFunctionArg) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - return ZT_RESULT_ERROR_BAD_PARAMETER; - - std::vector eps; - for(unsigned int i=0;icluster = new Cluster(RR,myId,eps,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg); - - return ZT_RESULT_OK; -#else - return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; -#endif -} - -ZT_ResultCode Node::clusterAddMember(unsigned int memberId) -{ -#ifdef ZT_ENABLE_CLUSTER - if (!RR->cluster) - return ZT_RESULT_ERROR_BAD_PARAMETER; - RR->cluster->addMember((uint16_t)memberId); - return ZT_RESULT_OK; -#else - return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION; -#endif -} - -void Node::clusterRemoveMember(unsigned int memberId) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->removeMember((uint16_t)memberId); -#endif -} - -void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len) -{ -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->handleIncomingStateMessage(msg,len); -#endif -} - -void Node::clusterStatus(ZT_ClusterStatus *cs) -{ - if (!cs) - return; -#ifdef ZT_ENABLE_CLUSTER - if (RR->cluster) - RR->cluster->status(*cs); - else -#endif - memset(cs,0,sizeof(ZT_ClusterStatus)); -} -*/ - /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -918,7 +841,7 @@ enum ZT_ResultCode ZT_Node_processStateUpdate( ZT_Node *node, void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len) { diff --git a/node/Node.hpp b/node/Node.hpp index f1209d00..17050d24 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -85,7 +85,7 @@ public: ZT_ResultCode processStateUpdate( void *tptr, ZT_StateObjectType type, - uint64_t id, + const uint64_t id[2], const void *data, unsigned int len); ZT_ResultCode processWirePacket( diff --git a/node/Path.hpp b/node/Path.hpp index 74b31d8d..a6f56d31 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -46,11 +46,6 @@ */ #define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1) -/** - * Maximum distance for a path - */ -#define ZT_PATH_DISTANCE_MAX 0xffff - namespace ZeroTier { class RuntimeEnvironment; @@ -125,7 +120,6 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), - _distance(ZT_PATH_DISTANCE_MAX), _addr(), _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) @@ -143,7 +137,6 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), - _distance(ZT_PATH_DISTANCE_MAX), _addr(addr), _localAddress(localAddress), _ipScope(addr.ipScope()) @@ -311,11 +304,6 @@ public: */ inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } - /** - * @return Distance (higher is further) - */ - inline unsigned int distance() const { return _distance; } - /** * @param lo Last out send * @param li Last in send @@ -344,7 +332,6 @@ private: volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; - volatile unsigned int _distance; InetAddress _addr; InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often diff --git a/node/Peer.cpp b/node/Peer.cpp index a7466296..18d05875 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -146,8 +146,8 @@ void Peer::received( path->updateLinkQuality((unsigned int)(packetId & 7)); if (hops == 0) { + // If this is a direct packet (no hops), update existing paths or learn new ones bool pathAlreadyKnown = false; - bool newPathLearned = false; { Mutex::Lock _l(_paths_m); @@ -188,7 +188,7 @@ void Peer::received( if (verb == Packet::VERB_OK) { potentialNewPeerPath->lr = now; potentialNewPeerPath->p = path; - newPathLearned = true; + _lastWroteState = 0; // force state write now } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); @@ -196,9 +196,6 @@ void Peer::received( } } } - - if (newPathLearned) - writeState(tPtr,now); } else if (this->trustEstablished(now)) { // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { @@ -270,6 +267,9 @@ void Peer::received( } } } + + if ((now - _lastWroteState) > ZT_PEER_STATE_WRITE_PERIOD) + writeState(tPtr,now); } bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) @@ -435,7 +435,7 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) void Peer::writeState(void *tPtr,const uint64_t now) { try { - Buffer b; + Buffer b; b.append((uint8_t)1); // version b.append(now); @@ -455,7 +455,6 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v4Path.p->lastOut()); b.append(_v4Path.p->lastIn()); b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); - b.append((uint16_t)_v4Path.p->distance()); _v4Path.p->address().serialize(b); _v4Path.p->localAddress().serialize(b); } @@ -464,29 +463,29 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v6Path.p->lastOut()); b.append(_v6Path.p->lastIn()); b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); - b.append((uint16_t)_v6Path.p->distance()); _v6Path.p->address().serialize(b); _v6Path.p->localAddress().serialize(b); } } - b.append(_lastReceive); - b.append(_lastNontrivialReceive); - b.append(_lastTriedMemorizedPath); - b.append(_lastDirectPathPushSent); - b.append(_lastDirectPathPushReceive); - b.append(_lastCredentialRequestSent); - b.append(_lastWhoisRequestReceived); - b.append(_lastEchoRequestReceived); - b.append(_lastComRequestReceived); - b.append(_lastComRequestSent); - b.append(_lastCredentialsReceived); - b.append(_lastTrustEstablishedPacketReceived); - - b.append(_vProto); - b.append(_vMajor); - b.append(_vMinor); - b.append(_vRevision); + // Save space by sending these as time since now at 100ms resolution + b.append((uint16_t)(std::max(now - _lastReceive,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastNontrivialReceive,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastTriedMemorizedPath,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastDirectPathPushSent,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastDirectPathPushReceive,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastCredentialRequestSent,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastWhoisRequestReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastEchoRequestReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastComRequestReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastComRequestSent,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastCredentialsReceived,(uint64_t)6553500) / 100)); + b.append((uint16_t)(std::max(now - _lastTrustEstablishedPacketReceived,(uint64_t)6553500) / 100)); + + b.append((uint8_t)_vProto); + b.append((uint8_t)_vMajor); + b.append((uint8_t)_vMinor); + b.append((uint16_t)_vRevision); b.append((uint16_t)0); // length of additional fields @@ -501,7 +500,7 @@ void Peer::writeState(void *tPtr,const uint64_t now) bool Peer::applyStateUpdate(const void *data,unsigned int len) { try { - Buffer b(data,len); + Buffer b(data,len); unsigned int ptr = 0; if (b[ptr++] != 1) @@ -510,6 +509,11 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) if (ts <= _lastReceivedStateTimestamp) return false; + Identity id; + ptr += id.deserialize(b,ptr); + if (id != _id) // sanity check + return false; + const unsigned int pathCount = (unsigned int)b[ptr++]; { Mutex::Lock _l(_paths_m); @@ -518,7 +522,6 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) const uint64_t lastOut = b.at(ptr); ptr += 8; const uint64_t lastIn = b.at(ptr); ptr += 8; const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; - const unsigned int distance = b.at(ptr); ptr += 2; InetAddress addr,localAddr; ptr += addr.deserialize(b,ptr); ptr += localAddr.deserialize(b,ptr); @@ -529,8 +532,9 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) case AF_INET6: p = &_v6Path; break; } if (p) { - if ( ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) && (p->p->distance() > distance) ) + if ( (!p->p) || ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) ) { p->p = RR->topology->getPath(localAddr,addr); + } p->lr = lr; p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); } @@ -538,22 +542,22 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) } } - _lastReceive = std::max(_lastReceive,b.at(ptr)); ptr += 8; - _lastNontrivialReceive = std::max(_lastNontrivialReceive,b.at(ptr)); ptr += 8; - _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,b.at(ptr)); ptr += 8; - _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,b.at(ptr)); ptr += 8; - _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,b.at(ptr)); ptr += 8; - _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,b.at(ptr)); ptr += 8; - _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,b.at(ptr)); ptr += 8; - _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,b.at(ptr)); ptr += 8; - _lastComRequestReceived = std::max(_lastComRequestReceived,b.at(ptr)); ptr += 8; - _lastComRequestSent = std::max(_lastComRequestSent,b.at(ptr)); ptr += 8; - _lastCredentialsReceived = std::max(_lastCredentialsReceived,b.at(ptr)); ptr += 8; - _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,b.at(ptr)); ptr += 8; - - _vProto = b.at(ptr); ptr += 2; - _vMajor = b.at(ptr); ptr += 2; - _vMinor = b.at(ptr); ptr += 2; + _lastReceive = std::max(_lastReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastNontrivialReceive = std::max(_lastNontrivialReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastComRequestReceived = std::max(_lastComRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastComRequestSent = std::max(_lastComRequestSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastCredentialsReceived = std::max(_lastCredentialsReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; + + _vProto = (uint16_t)b[ptr++]; + _vMajor = (uint16_t)b[ptr++]; + _vMinor = (uint16_t)b[ptr++]; _vRevision = b.at(ptr); ptr += 2; _lastReceivedStateTimestamp = ts; @@ -563,4 +567,25 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) return false; } +SharedPtr Peer::createFromStateUpdate(const RuntimeEnvironment *renv,void *tPtr,const void *data,unsigned int len) +{ + try { + Identity id; + { + Buffer b(data,len); + unsigned int ptr = 0; + if (b[ptr++] != 1) + return SharedPtr(); + ptr += 8; // skip TS, don't care + id.deserialize(b,ptr); + } + if (id) { + const SharedPtr p(new Peer(renv,renv->identity,id)); + if (p->applyStateUpdate(data,len)) + return renv->topology->addPeer(tPtr,p); + } + } catch ( ... ) {} + return SharedPtr(); +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index d6b7dad9..f0eb3ee8 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -51,6 +51,8 @@ #include "Mutex.hpp" #include "NonCopyable.hpp" +#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) + namespace ZeroTier { /** @@ -194,9 +196,10 @@ public: bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); /** - * Write current peer state to external storage / cluster network + * Write object state to external storage and/or cluster network * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time */ void writeState(void *tPtr,const uint64_t now); @@ -437,6 +440,17 @@ public: return false; } + /** + * Create a peer from a remote state update + * + * @param renv Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param data State update data + * @param len State update length + * @return Peer or NULL if data was invalid + */ + static SharedPtr createFromStateUpdate(const RuntimeEnvironment *renv,void *tPtr,const void *data,unsigned int len); + private: struct _PeerPath { diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index d8e1d699..ee0c8c24 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -30,8 +30,8 @@ #include #include "Constants.hpp" +#include "Utils.hpp" #include "Identity.hpp" -#include "Mutex.hpp" namespace ZeroTier { @@ -58,10 +58,13 @@ public: ,mc((Multicaster *)0) ,topology((Topology *)0) ,sa((SelfAwareness *)0) -#ifdef ZT_ENABLE_CLUSTER - ,cluster((Cluster *)0) -#endif { + Utils::getSecureRandom(&instanceId,sizeof(instanceId)); + } + + ~RuntimeEnvironment() + { + Utils::burn(reinterpret_cast(const_cast(secretIdentityStr.data())),(unsigned int)secretIdentityStr.length()); } // Node instance that owns this RuntimeEnvironment @@ -87,9 +90,11 @@ public: Multicaster *mc; Topology *topology; SelfAwareness *sa; -#ifdef ZT_ENABLE_CLUSTER - Cluster *cluster; -#endif + + /** + * A random integer identifying this run of ZeroTier + */ + uint32_t instanceId; }; } // namespace ZeroTier diff --git a/node/Switch.cpp b/node/Switch.cpp index 2be54b37..cbd73a83 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -108,13 +108,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd const Address destination(fragment.destination()); if (destination != RR->identity.address()) { -#ifdef ZT_ENABLE_CLUSTER - const bool isClusterFrontplane = ((RR->cluster)&&(RR->cluster->isClusterPeerFrontplane(fromAddr))); -#else - const bool isClusterFrontplane = false; -#endif - - if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (!isClusterFrontplane) ) + if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) ) return; if (fragment.hops() < ZT_RELAY_MAX_HOPS) { @@ -124,13 +118,6 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd // It wouldn't hurt anything, just redundant and unnecessary. SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(!isClusterFrontplane)) { - RR->cluster->relayViaCluster(Address(),destination,fragment.data(),fragment.size(),false); - return; - } -#endif - // Don't know peer or no direct path -- so relay via someone upstream relayTo = RR->topology->getUpstreamPeer(); if (relayTo) @@ -197,13 +184,8 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); -#ifdef ZT_ENABLE_CLUSTER - if ( (source == RR->identity.address()) && ((!RR->cluster)||(!RR->cluster->isClusterPeerFrontplane(fromAddr))) ) - return; -#else if (source == RR->identity.address()) return; -#endif if (destination != RR->identity.address()) { if ( (!RR->topology->amRoot()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) @@ -212,12 +194,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd Packet packet(data,len); if (packet.hops() < ZT_RELAY_MAX_HOPS) { -#ifdef ZT_ENABLE_CLUSTER - if (source != RR->identity.address()) // don't increment hops for cluster frontplane relays - packet.incrementHops(); -#else packet.incrementHops(); -#endif SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { @@ -277,12 +254,6 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd } } } else { -#ifdef ZT_ENABLE_CLUSTER - if ((RR->cluster)&&(source != RR->identity.address())) { - RR->cluster->relayViaCluster(source,destination,packet.data(),packet.size(),_shouldUnite(now,source,destination)); - return; - } -#endif relayTo = RR->topology->getUpstreamPeer(&source,1,true); if (relayTo) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); @@ -769,14 +740,6 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) const uint64_t now = RR->node->now(); const Address destination(packet.destination()); -#ifdef ZT_ENABLE_CLUSTER - uint64_t clusterMostRecentTs = 0; - int clusterMostRecentMemberId = -1; - uint8_t clusterPeerSecret[ZT_PEER_SECRET_KEY_LENGTH]; - if (RR->cluster) - clusterMostRecentMemberId = RR->cluster->checkSendViaCluster(destination,clusterMostRecentTs,clusterPeerSecret); -#endif - const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); if (peer) { /* First get the best path, and if it's dead (and this is not a root) @@ -788,74 +751,37 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) viaPath = peer->getBestPath(now,false); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { -#ifdef ZT_ENABLE_CLUSTER - if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) { -#endif - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); - viaPath->sent(now); - } -#ifdef ZT_ENABLE_CLUSTER + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { + peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); + viaPath->sent(now); } -#endif viaPath.zero(); } -#ifdef ZT_ENABLE_CLUSTER - if (clusterMostRecentMemberId >= 0) { - if ((viaPath)&&(viaPath->lastIn() < clusterMostRecentTs)) - viaPath.zero(); - } else if (!viaPath) { -#else if (!viaPath) { -#endif peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known const SharedPtr relay(RR->topology->getUpstreamPeer()); if ( (!relay) || (!(viaPath = relay->getBestPath(now,false))) ) { if (!(viaPath = peer->getBestPath(now,true))) return false; } -#ifdef ZT_ENABLE_CLUSTER } -#else - } -#endif } else { -#ifdef ZT_ENABLE_CLUSTER - if (clusterMostRecentMemberId < 0) { -#else - requestWhois(tPtr,destination); - return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly -#endif -#ifdef ZT_ENABLE_CLUSTER - } -#endif + requestWhois(tPtr,destination); + return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); packet.setFragmented(chunkSize < packet.size()); -#ifdef ZT_ENABLE_CLUSTER - const uint64_t trustedPathId = (viaPath) ? RR->topology->getOutboundPathTrust(viaPath->address()) : 0; - if (trustedPathId) { - packet.setTrusted(trustedPathId); - } else { - packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt,(viaPath) ? viaPath->nextOutgoingCounter() : 0); - } -#else const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); if (trustedPathId) { packet.setTrusted(trustedPathId); } else { packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); } -#endif -#ifdef ZT_ENABLE_CLUSTER - if ( ((viaPath)&&(viaPath->send(RR,tPtr,packet.data(),chunkSize,now))) || ((clusterMostRecentMemberId >= 0)&&(RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,packet.data(),chunkSize))) ) { -#else if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { -#endif if (chunkSize < packet.size()) { // Too big for one packet, fragment the rest unsigned int fragStart = chunkSize; @@ -868,14 +794,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) for(unsigned int fno=1;fnosend(RR,tPtr,frag.data(),frag.size(),now); - else if (clusterMostRecentMemberId >= 0) - RR->cluster->sendViaCluster(clusterMostRecentMemberId,destination,frag.data(),frag.size()); -#else viaPath->send(RR,tPtr,frag.data(),frag.size(),now); -#endif fragStart += chunkSize; remaining -= chunkSize; } diff --git a/node/Topology.cpp b/node/Topology.cpp index be116b28..09a1a895 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -108,8 +108,6 @@ SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) np = hp; } - saveIdentity(tPtr,np->identity()); - return np; } @@ -128,18 +126,20 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) } try { - Identity id(_getIdentity(tPtr,zta)); - if (id) { - SharedPtr np(new Peer(RR,RR->identity,id)); - { - Mutex::Lock _l(_peers_m); - SharedPtr &ap = _peers[zta]; - if (!ap) - ap.swap(np); + char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; + uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_STATE,idbuf,buf,(unsigned int)sizeof(buf)); + if (len > 0) { + Mutex::Lock _l(_peers_m); + SharedPtr &ap = _peers[zta]; + if (ap) return ap; - } + ap = Peer::createFromStateUpdate(RR,tPtr,buf,len); + if (!ap) + _peers.erase(zta); + return ap; } - } catch ( ... ) {} // invalid identity on disk? + } catch ( ... ) {} // ignore invalid identities or other strage failures return SharedPtr(); } @@ -154,17 +154,7 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) if (ap) return (*ap)->identity(); } - return _getIdentity(tPtr,zta); -} - -void Topology::saveIdentity(void *tPtr,const Identity &id) -{ - if (id) { - const std::string tmp(id.toString(false)); - uint64_t idtmp[2]; - idtmp[0] = id.address().toInt(); idtmp[1] = 0; - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp.data(),(unsigned int)tmp.length()); - } + return Identity(); } SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) @@ -423,21 +413,6 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now) } } -Identity Topology::_getIdentity(void *tPtr,const Address &zta) -{ - char tmp[512]; - uint64_t idtmp[2]; - idtmp[0] = zta.toInt(); idtmp[1] = 0; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_IDENTITY,idtmp,tmp,sizeof(tmp) - 1); - if (n > 0) { - tmp[n] = (char)0; - try { - return Identity(tmp); - } catch ( ... ) {} // ignore invalid IDs - } - return Identity(); -} - void Topology::_memoizeUpstreams(void *tPtr) { // assumes _upstreams_m and _peers_m are locked @@ -450,10 +425,8 @@ void Topology::_memoizeUpstreams(void *tPtr) } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { _upstreamAddresses.push_back(i->identity.address()); SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { + if (!hp) hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(tPtr,i->identity); - } } } @@ -464,10 +437,8 @@ void Topology::_memoizeUpstreams(void *tPtr) } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { _upstreamAddresses.push_back(i->identity.address()); SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { + if (!hp) hp = new Peer(RR,RR->identity,i->identity); - saveIdentity(tPtr,i->identity); - } } } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 9bc7c0d8..32e38dd3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -81,6 +81,13 @@ public: */ SharedPtr getPeer(void *tPtr,const Address &zta); + /** + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param zta ZeroTier address of peer + * @return Identity or NULL identity if not found + */ + Identity getIdentity(void *tPtr,const Address &zta); + /** * Get a peer only if it is presently in memory (no disk cache) * @@ -116,26 +123,6 @@ public: return p; } - /** - * Get the identity of a peer - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param zta ZeroTier address of peer - * @return Identity or NULL Identity if not found - */ - Identity getIdentity(void *tPtr,const Address &zta); - - /** - * Cache an identity - * - * This is done automatically on addPeer(), and so is only useful for - * cluster identity replication. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param id Identity to cache - */ - void saveIdentity(void *tPtr,const Identity &id); - /** * Get the current best upstream peer * diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index a0b47367..b1fe5921 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -180,7 +180,7 @@ public: const unsigned long pid = (unsigned long)getpid(); // Get all device names - Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid); + Utils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid); FILE *procf = fopen(fn,"r"); if (procf) { while (fgets(tmp,sizeof(tmp),procf)) { @@ -196,7 +196,7 @@ public: } // Get IPv6 addresses (and any device names we don't already know) - Utils::snprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); + Utils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); procf = fopen(fn,"r"); if (procf) { while (fgets(tmp,sizeof(tmp),procf)) { diff --git a/service/OneService.cpp b/service/OneService.cpp index f949f348..b5b11111 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -154,9 +154,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } // How often to check for local interface addresses #define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 -// Clean files from iddb.d that are older than this (60 days) -#define ZT_IDDB_CLEANUP_AGE 5184000000ULL - // Maximum write buffer size for outgoing TCP connections (sanity limit) #define ZT_TCP_MAX_WRITEQ_SIZE 33554432 @@ -414,7 +411,6 @@ public: const std::string _homePath; std::string _authToken; std::string _controllerDbPath; - const std::string _iddbPath; const std::string _networksPath; const std::string _moonsPath; @@ -513,7 +509,6 @@ public: OneServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : ".") ,_controllerDbPath(_homePath + ZT_PATH_SEPARATOR_S "controller.d") - ,_iddbPath(_homePath + ZT_PATH_SEPARATOR_S "iddb.d") ,_networksPath(_homePath + ZT_PATH_SEPARATOR_S "networks.d") ,_moonsPath(_homePath + ZT_PATH_SEPARATOR_S "moons.d") ,_controller((EmbeddedNetworkController *)0) @@ -732,6 +727,9 @@ public: } #endif + // Delete legacy iddb.d if present (cleanup) + OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str()); + // Network controller is now enabled by default for desktop and server _controller = new EmbeddedNetworkController(_node,_controllerDbPath.c_str()); _node->setNetconfMaster((void *)_controller); @@ -781,7 +779,6 @@ public: uint64_t lastBindRefresh = 0; uint64_t lastUpdateCheck = clockShouldBe; uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle - uint64_t lastCleanedIddb = 0; uint64_t lastTcpCheck = 0; for(;;) { _run_m.lock(); @@ -797,12 +794,6 @@ public: const uint64_t now = OSUtils::now(); - // Clean iddb.d on start and every 24 hours - if ((now - lastCleanedIddb) > 86400000) { - lastCleanedIddb = now; - OSUtils::cleanDirectory(_iddbPath.c_str(),now - ZT_IDDB_CLEANUP_AGE); - } - // Attempt to detect sleep/wake events by detecting delay overruns bool restarted = false; if ((now > clockShouldBe)&&((now - clockShouldBe) > 10000)) { @@ -1027,7 +1018,7 @@ public: return NULL; } - virtual Node * getNode() + virtual Node *getNode() { return _node; } @@ -1903,27 +1894,16 @@ public: char *const outdata = const_cast(tc->writeq.data()) + startpos; encryptClusterMessage(outdata,mlen); - } - - void replicateStateObjectToCluster(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,const uint64_t everyoneBut) - { - std::vector sentTo; - if (everyoneBut) - sentTo.push_back(everyoneBut); - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) { - TcpConnection *const c = *ci; - if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) { - sentTo.push_back(c->clusterMemberId); - replicateStateObject(type,id,data,len,c); - } - } + tc->writeq.append(outdata,mlen); } void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { - char p[4096]; + char buf[65535]; + char p[1024]; + FILE *f; bool secure = false; + switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); @@ -1932,13 +1912,14 @@ public: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); secure = true; break; - case ZT_STATE_OBJECT_PEER_IDENTITY: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id[0]); - break; + //case ZT_STATE_OBJECT_PEER_STATE: + // break; case ZT_STATE_OBJECT_NETWORK_CONFIG: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); secure = true; break; + //case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: + // break; case ZT_STATE_OBJECT_PLANET: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; @@ -1949,17 +1930,30 @@ public: p[0] = (char)0; break; } + if (p[0]) { if (len >= 0) { - FILE *f = fopen(p,"w"); + // Check to see if we've already written this first. This reduces + // redundant writes and I/O overhead on most platforms and has + // little effect on others. + f = fopen(p,"r"); + bool redundant = false; if (f) { - if (fwrite(data,len,1,f) != 1) - fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + long l = (long)fread(buf,1,sizeof(buf),f); fclose(f); - if (secure) - OSUtils::lockDownFile(p,false); - } else { - fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + redundant = ((l == (long)len)&&(memcmp(data,buf,l) == 0)); + } + if (!redundant) { + f = fopen(p,"w"); + if (f) { + if (fwrite(data,len,1,f) != 1) + fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + fclose(f); + if (secure) + OSUtils::lockDownFile(p,false); + } else { + fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + } } } else { OSUtils::rm(p); @@ -2314,7 +2308,7 @@ public: break; case CLUSTER_MESSAGE_STATE_OBJECT: - if (mlen >= 42) { // type + object ID + [data] + if (mlen > 42) { // type + object ID + [data] uint64_t objId[2]; objId[0] = ( ((uint64_t)data[26] << 56) | @@ -2336,10 +2330,8 @@ public: ((uint64_t)data[40] << 8) | (uint64_t)data[41] ); - if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId[0],data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) { + if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)); - replicateStateObjectToCluster((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42),tc->clusterMemberId); - } } break; @@ -2558,7 +2550,18 @@ public: inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { writeStateObject(type,id,data,len); - replicateStateObjectToCluster(type,id,data,len,0); + + std::vector sentTo; + { + Mutex::Lock _l(_tcpConnections_m); + for(std::vector::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) { + TcpConnection *const c = *ci; + if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) { + sentTo.push_back(c->clusterMemberId); + replicateStateObject(type,id,data,len,c); + } + } + } } inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) @@ -2571,9 +2574,6 @@ public: case ZT_STATE_OBJECT_IDENTITY_SECRET: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); break; - case ZT_STATE_OBJECT_PEER_IDENTITY: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "iddb.d/%.10llx",_homePath.c_str(),(unsigned long long)id); - break; case ZT_STATE_OBJECT_NETWORK_CONFIG: Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); break; -- cgit v1.2.3 From f18158a52d28c14352018a68d328f41fcdb7966f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 11:45:22 -0700 Subject: . --- include/ZeroTierOne.h | 135 ++-------- node/IncomingPacket.cpp | 14 +- node/Node.cpp | 130 +--------- node/Node.hpp | 14 +- node/Path.cpp | 2 +- node/Path.hpp | 51 ++-- node/Peer.cpp | 59 ++--- node/Peer.hpp | 12 +- node/RuntimeEnvironment.hpp | 10 +- node/SelfAwareness.cpp | 4 +- node/SelfAwareness.hpp | 10 +- node/Switch.cpp | 8 +- node/Switch.hpp | 4 +- node/Topology.cpp | 4 +- node/Topology.hpp | 4 +- osdep/Binder.hpp | 109 ++------ service/OneService.cpp | 609 +++++--------------------------------------- 17 files changed, 198 insertions(+), 981 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 133ae340..180e5cd2 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -229,11 +229,6 @@ extern "C" { */ #define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL -/** - * A null/empty sockaddr (all zero) to signify an unspecified socket address - */ -extern const struct sockaddr_storage ZT_SOCKADDR_NULL; - /****************************************************************************/ /* Structures and other types */ /****************************************************************************/ @@ -1067,21 +1062,6 @@ typedef struct /** * ZeroTier core state objects - * - * All of these objects can be persisted if desired. To preserve the - * identity of a node and its address, the identity (public and secret) - * must be saved at a minimum. - * - * State objects actually have two IDs (uint64_t[2]). If only one is - * listed the second ([1]) should be zero and is ignored in storage - * and replication. - * - * All state objects should be replicated in cluster mode. The reference - * clustering implementation uses a rumor mill algorithm in which state - * updates that are accepted with RESULT_OK (but not RESULT_OK_IGNORED) - * are flooded to all connected cluster peers. This results in updates - * being flooded across the cluster until all cluster members have the - * latest. */ enum ZT_StateObjectType { @@ -1108,36 +1088,6 @@ enum ZT_StateObjectType */ ZT_STATE_OBJECT_IDENTITY_SECRET = 2, - /** - * A peer to which this node is communicating - * - * Object ID: peer address - * Canonical path: /peers.d/
(10-digit hex address) - * Persistence: optional, can be purged at any time - */ - ZT_STATE_OBJECT_PEER_STATE = 3, - - /** - * Network configuration - * - * Object ID: peer address - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist - */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 4, - - /** - * Network membership (network X peer intersection) - * - * If these are persisted they must be restored after peer states and - * network configs. Otherwise they are ignored. - * - * Object ID: [0] network ID, [1] peer address - * Canonical path: /networks.d//members.d/
- * Persistence: optional (not usually needed) - */ - ZT_STATE_OBJECT_NETWORK_MEMBERSHIP = 5, - /** * The planet (there is only one per... well... planet!) * @@ -1145,7 +1095,7 @@ enum ZT_StateObjectType * Canonical path: /planet * Persistence: recommended */ - ZT_STATE_OBJECT_PLANET = 6, + ZT_STATE_OBJECT_PLANET = 3, /** * A moon (federated root set) @@ -1154,12 +1104,25 @@ enum ZT_StateObjectType * Canonical path: /moons.d/.moon (16-digit hex ID) * Persistence: required if moon memberships should persist */ - ZT_STATE_OBJECT_MOON = 7, + ZT_STATE_OBJECT_MOON = 4, /** - * IDs above this value will not be used by the core (and could be used as implementation-specific IDs) + * Peer and related state + * + * Object ID: peer address + * Canonical path: /peers.d/ (10-digit address + * Persistence: optional, can be cleared at any time + */ + ZT_STATE_OBJECT_PEER = 5, + + /** + * Network configuration + * + * Object ID: peer address + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist */ - ZT_STATE_OBJECT__MAX_ID = 255 + ZT_STATE_OBJECT_NETWORK_CONFIG = 6 }; /** @@ -1277,17 +1240,15 @@ typedef int (*ZT_StateGetFunction)( * Parameters: * (1) Node * (2) User pointer - * (3) Local interface address + * (3) Local socket or -1 for "all" or "any" * (4) Remote address * (5) Packet data * (6) Packet length * (7) Desired IP TTL or 0 to use default * - * If there is only one local interface it is safe to ignore the local - * interface address. Otherwise if running with multiple interfaces, the - * correct local interface should be chosen by address unless NULL. If - * the ss_family field is zero (NULL address), a random or preferred - * default interface should be used. + * If there is only one local socket, the local socket can be ignored. + * If the local socket is -1, the packet should be sent out from all + * bound local sockets or a random bound local socket. * * If TTL is nonzero, packets should have their IP TTL value set to this * value if possible. If this is not possible it is acceptable to ignore @@ -1301,7 +1262,7 @@ typedef int (*ZT_WirePacketSendFunction)( ZT_Node *, /* Node */ void *, /* User ptr */ void *, /* Thread ptr */ - const struct sockaddr_storage *, /* Local address */ + int64_t, /* Local socket */ const struct sockaddr_storage *, /* Remote address */ const void *, /* Packet data */ unsigned int, /* Packet length */ @@ -1314,7 +1275,7 @@ typedef int (*ZT_WirePacketSendFunction)( * (1) Node * (2) User pointer * (3) ZeroTier address or 0 for none/any - * (4) Local interface address + * (4) Local socket or -1 if unknown * (5) Remote address * * This function must return nonzero (true) if the path should be used. @@ -1333,7 +1294,7 @@ typedef int (*ZT_PathCheckFunction)( void *, /* User ptr */ void *, /* Thread ptr */ uint64_t, /* ZeroTier address */ - const struct sockaddr_storage *, /* Local address */ + int64_t, /* Local socket or -1 if unknown */ const struct sockaddr_storage *); /* Remote address */ /** @@ -1441,57 +1402,13 @@ enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct */ void ZT_Node_delete(ZT_Node *node); -/** - * Notify node of an update to a state object - * - * This can be called after node startup to restore cached state objects such - * as network configurations for joined networks, planet, moons, etc. See - * the documentation of ZT_StateObjectType for more information. It's okay - * to call this for everything in the object store, but note that the node - * will automatically query for some core objects like identities so supplying - * these via this function is not necessary. - * - * Unless clustering is being implemented this function doesn't need to be - * used after startup. It could be called in response to filesystem changes - * to allow some degree of live configurability by filesystem observation - * but this kind of thing is entirely optional. - * - * The return value of this function indicates whether the update was accepted - * as new. A return value of ZT_RESULT_OK indicates that the node gleaned new - * information from this update and that therefore (in cluster rumor mill mode) - * this update should be distributed to other members of a cluster. A return - * value of ZT_RESULT_OK_IGNORED indicates that the object did not provide any - * new information and therefore should not be propagated in a cluster. - * - * If clustering isn't being implemented the return value of this function can - * generally be ignored. - * - * ZT_RESULT_ERROR_BAD_PARAMETER can be returned if the parameter was invalid - * or not applicable. Object stores may delete the object in this case. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param type State object type - * @param id State object ID (if object type has only one ID, second should be zero) - * @param data State object data - * @param len Length of state object data in bytes - * @return ZT_RESULT_OK if object was accepted or ZT_RESULT_OK_IGNORED if non-informative, error if object was invalid - */ -enum ZT_ResultCode ZT_Node_processStateUpdate( - ZT_Node *node, - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len); - /** * Process a packet received from the physical wire * * @param node Node instance * @param tptr Thread pointer to pass to functions/callbacks resulting from this call * @param now Current clock in milliseconds - * @param localAddress Local address, or point to ZT_SOCKADDR_NULL if unspecified + * @param localSocket Local socket (you can use 0 if only one local socket is bound and ignore this) * @param remoteAddress Origin of packet * @param packetData Packet data * @param packetLength Packet length @@ -1502,7 +1419,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0548387b..f0be96f9 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -309,7 +309,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool if (ptr < size()) { ptr += externalSurfaceAddress.deserialize(*this,ptr); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); + RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); } // Get primary planet world ID and world timestamp if present @@ -495,7 +495,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) - RR->sa->iam(tPtr,peer->address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); + RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); } break; case Packet::VERB_WHOIS: @@ -613,9 +613,9 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localAddress(),atAddr)) { - RR->node->putPacket(tPtr,_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localAddress(),atAddr,RR->node->now(),false,0); + if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { + RR->node->putPacket(tPtr,_path->localSocket(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } else { TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); @@ -1197,7 +1197,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) // peer->setClusterPreferred(a); @@ -1214,7 +1214,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path + (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) // peer->setClusterPreferred(a); diff --git a/node/Node.cpp b/node/Node.cpp index 4ffe496c..4b598f61 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -47,8 +47,6 @@ #include "SelfAwareness.hpp" #include "Network.hpp" -const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; - namespace ZeroTier { /****************************************************************************/ @@ -137,114 +135,17 @@ Node::~Node() delete RR->sw; } -ZT_ResultCode Node::processStateUpdate( - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len) -{ - ZT_ResultCode r = ZT_RESULT_OK_IGNORED; - switch(type) { - - case ZT_STATE_OBJECT_PEER_STATE: - if (len) { - const SharedPtr p(RR->topology->getPeer(tptr,Address(id[0]))); - if (p) { - r = (p->applyStateUpdate(data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; - } else { - r = (Peer::createFromStateUpdate(RR,tptr,data,len)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; - } - } - break; - - case ZT_STATE_OBJECT_NETWORK_CONFIG: - if (len <= (ZT_NETWORKCONFIG_DICT_CAPACITY - 1)) { - if (len < 2) { - Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id[0]]; - if (!nw) { - nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,(const NetworkConfig *)0)); - r = ZT_RESULT_OK; - } - } else { - Dictionary *dict = new Dictionary(reinterpret_cast(data),len); - try { - NetworkConfig *nconf = new NetworkConfig(); - try { - if (nconf->fromDictionary(*dict)) { - Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[id[0]]; - if (nw) { - switch (nw->setConfiguration(tptr,*nconf,false)) { - default: - r = ZT_RESULT_ERROR_BAD_PARAMETER; - break; - case 1: - r = ZT_RESULT_OK_IGNORED; - break; - case 2: - r = ZT_RESULT_OK; - break; - } - } else { - nw = SharedPtr(new Network(RR,tptr,id[0],(void *)0,nconf)); - } - } else { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - } catch ( ... ) { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - delete nconf; - } catch ( ... ) { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - delete dict; - } - } else { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - break; - - case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: - if (len) { - } - break; - - case ZT_STATE_OBJECT_PLANET: - case ZT_STATE_OBJECT_MOON: - if ((len)&&(len <= ZT_WORLD_MAX_SERIALIZED_LENGTH)) { - World w; - try { - w.deserialize(Buffer(data,len)); - if (( (w.type() == World::TYPE_MOON)&&(type == ZT_STATE_OBJECT_MOON) )||( (w.type() == World::TYPE_PLANET)&&(type == ZT_STATE_OBJECT_PLANET) )) { - r = (RR->topology->addWorld(tptr,w,false)) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; - } - } catch ( ... ) { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - } else { - r = ZT_RESULT_ERROR_BAD_PARAMETER; - } - break; - - default: break; - } - return r; -} - ZT_ResultCode Node::processWirePacket( void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, volatile uint64_t *nextBackgroundTaskDeadline) { _now = now; - RR->sw->onRemotePacket(tptr,*(reinterpret_cast(localAddress)),*(reinterpret_cast(remoteAddress)),packetData,packetLength); + RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast(remoteAddress)),packetData,packetLength); return ZT_RESULT_OK; } @@ -317,7 +218,7 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(_tPtr,up->localAddress(),up->address(),_now,up->nextOutgoingCounter()); + p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now,up->nextOutgoingCounter()); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); @@ -617,7 +518,7 @@ void Node::setNetconfMaster(void *networkControllerInstance) /* Node methods used only within node/ */ /****************************************************************************/ -bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress) { if (!Path::isAddressValidForPath(remoteAddress)) return false; @@ -640,7 +541,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons } } - return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),reinterpret_cast(&localAddress),reinterpret_cast(&remoteAddress)) != 0) : true); + return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),localSocket,reinterpret_cast(&remoteAddress)) != 0) : true); } #ifdef ZT_TRACE @@ -837,35 +738,18 @@ void ZT_Node_delete(ZT_Node *node) } catch ( ... ) {} } -enum ZT_ResultCode ZT_Node_processStateUpdate( - ZT_Node *node, - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len) -{ - try { - return reinterpret_cast(node)->processStateUpdate(tptr,type,id,data,len); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } -} - enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, volatile uint64_t *nextBackgroundTaskDeadline) { try { - return reinterpret_cast(node)->processWirePacket(tptr,now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { diff --git a/node/Node.hpp b/node/Node.hpp index 17050d24..55491b06 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -82,16 +82,10 @@ public: // Public API Functions ---------------------------------------------------- - ZT_ResultCode processStateUpdate( - void *tptr, - ZT_StateObjectType type, - const uint64_t id[2], - const void *data, - unsigned int len); ZT_ResultCode processWirePacket( void *tptr, uint64_t now, - const struct sockaddr_storage *localAddress, + int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, @@ -129,13 +123,13 @@ public: inline uint64_t now() const throw() { return _now; } - inline bool putPacket(void *tPtr,const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) + inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { return (_cb.wirePacketSendFunction( reinterpret_cast(this), _uPtr, tPtr, - reinterpret_cast(&localAddress), + localSocket, reinterpret_cast(&addr), data, len, @@ -205,7 +199,7 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif - bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const InetAddress &localAddress,const InetAddress &remoteAddress); + bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress); inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); diff --git a/node/Path.cpp b/node/Path.cpp index a5fe1aa7..9dc9aba5 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -32,7 +32,7 @@ namespace ZeroTier { bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) { - if (RR->node->putPacket(tPtr,_localAddress,address(),data,len)) { + if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { _lastOut = now; return true; } diff --git a/node/Path.hpp b/node/Path.hpp index a6f56d31..854b28e2 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -66,49 +66,28 @@ public: public: HashKey() {} - HashKey(const InetAddress &l,const InetAddress &r) + HashKey(const int64_t l,const InetAddress &r) { - // This is an ad-hoc bit packing algorithm to yield unique keys for - // remote addresses and their local-side counterparts if defined. - // Portability across runtimes is not needed. if (r.ss_family == AF_INET) { _k[0] = (uint64_t)reinterpret_cast(&r)->sin_addr.s_addr; _k[1] = (uint64_t)reinterpret_cast(&r)->sin_port; - if (l.ss_family == AF_INET) { - _k[2] = (uint64_t)reinterpret_cast(&l)->sin_addr.s_addr; - _k[3] = (uint64_t)reinterpret_cast(&r)->sin_port; - } else { - _k[2] = 0; - _k[3] = 0; - } + _k[2] = (uint64_t)l; } else if (r.ss_family == AF_INET6) { - const uint8_t *a = reinterpret_cast(reinterpret_cast(&r)->sin6_addr.s6_addr); - uint8_t *b = reinterpret_cast(_k); - for(unsigned int i=0;i<16;++i) b[i] = a[i]; - _k[2] = ~((uint64_t)reinterpret_cast(&r)->sin6_port); - if (l.ss_family == AF_INET6) { - _k[2] ^= ((uint64_t)reinterpret_cast(&r)->sin6_port) << 32; - a = reinterpret_cast(reinterpret_cast(&l)->sin6_addr.s6_addr); - b += 24; - for(unsigned int i=0;i<8;++i) b[i] = a[i]; - a += 8; - for(unsigned int i=0;i<8;++i) b[i] ^= a[i]; - } + memcpy(_k,reinterpret_cast(&r)->sin6_addr.s6_addr,16); + _k[2] = ((uint64_t)reinterpret_cast(&r)->sin6_port << 32) ^ (uint64_t)l; } else { - _k[0] = 0; - _k[1] = 0; - _k[2] = 0; - _k[3] = 0; + memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress))); + _k[2] += (uint64_t)l; } } - inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2] + _k[3]); } + inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); } - inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) && (_k[3] == k._k[3]) ); } + inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); } inline bool operator!=(const HashKey &k) const { return (!(*this == k)); } private: - uint64_t _k[4]; + uint64_t _k[3]; }; Path() : @@ -116,29 +95,29 @@ public: _lastIn(0), _lastTrustEstablishedPacketReceived(0), _incomingLinkQualityFastLog(0xffffffffffffffffULL), + _localSocket(-1), _incomingLinkQualitySlowLogPtr(0), _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), _addr(), - _localAddress(), _ipScope(InetAddress::IP_SCOPE_NONE) { for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } - Path(const InetAddress &localAddress,const InetAddress &addr) : + Path(const int64_t localSocket,const InetAddress &addr) : _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), _incomingLinkQualityFastLog(0xffffffffffffffffULL), + _localSocket(localSocket), _incomingLinkQualitySlowLogPtr(0), _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), _addr(addr), - _localAddress(localAddress), _ipScope(addr.ipScope()) { for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) @@ -210,9 +189,9 @@ public: inline void sent(const uint64_t t) { _lastOut = t; } /** - * @return Address of local side of this path or NULL if unspecified + * @return Local socket as specified by external code */ - inline const InetAddress &localAddress() const { return _localAddress; } + inline const int64_t localSocket() const { return _localSocket; } /** * @return Physical address @@ -328,12 +307,12 @@ private: volatile uint64_t _lastIn; volatile uint64_t _lastTrustEstablishedPacketReceived; volatile uint64_t _incomingLinkQualityFastLog; + int64_t _localSocket; volatile unsigned long _incomingLinkQualitySlowLogPtr; volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; InetAddress _addr; - InetAddress _localAddress; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often volatile uint8_t _incomingLinkQualitySlowLog[32]; AtomicCounter __refCount; diff --git a/node/Peer.cpp b/node/Peer.cpp index 18d05875..875d651e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -154,25 +154,21 @@ void Peer::received( if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { const struct sockaddr_in *const r = reinterpret_cast(&(path->address())); const struct sockaddr_in *const l = reinterpret_cast(&(_v4Path.p->address())); - const struct sockaddr_in *const rl = reinterpret_cast(&(path->localAddress())); - const struct sockaddr_in *const ll = reinterpret_cast(&(_v4Path.p->localAddress())); - if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) { + if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(path->localSocket() == _v4Path.p->localSocket())) { _v4Path.lr = now; pathAlreadyKnown = true; } } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { const struct sockaddr_in6 *const r = reinterpret_cast(&(path->address())); const struct sockaddr_in6 *const l = reinterpret_cast(&(_v6Path.p->address())); - const struct sockaddr_in6 *const rl = reinterpret_cast(&(path->localAddress())); - const struct sockaddr_in6 *const ll = reinterpret_cast(&(_v6Path.p->localAddress())); - if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) { + if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(path->localSocket() == _v6Path.p->localSocket())) { _v6Path.lr = now; pathAlreadyKnown = true; } } } - if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) { + if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) { Mutex::Lock _l(_paths_m); _PeerPath *potentialNewPeerPath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { @@ -191,7 +187,7 @@ void Peer::received( _lastWroteState = 0; // force state write now } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); - attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter()); + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } } @@ -318,7 +314,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) return SharedPtr(); } -void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -360,21 +356,21 @@ void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress & if (atAddress) { outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC - RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); outp.armor(_key,true,counter); - RR->node->putPacket(tPtr,localAddr,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { - sendHELLO(tPtr,localAddr,atAddress,now,counter); + sendHELLO(tPtr,localSocket,atAddress,now,counter); } } @@ -402,13 +398,13 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) if (v6lr > v4lr) { if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); _v6Path.p->sent(now); return true; } } else if (v4lr) { if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); _v4Path.p->sent(now); return true; } @@ -416,13 +412,13 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) } else { if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); _v4Path.p->sent(now); return true; } } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); _v6Path.p->sent(now); return true; } @@ -456,7 +452,6 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v4Path.p->lastIn()); b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); _v4Path.p->address().serialize(b); - _v4Path.p->localAddress().serialize(b); } if (_v6Path.lr) { b.append(_v6Path.lr); @@ -464,7 +459,6 @@ void Peer::writeState(void *tPtr,const uint64_t now) b.append(_v6Path.p->lastIn()); b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); _v6Path.p->address().serialize(b); - _v6Path.p->localAddress().serialize(b); } } @@ -491,7 +485,7 @@ void Peer::writeState(void *tPtr,const uint64_t now) uint64_t tmp[2]; tmp[0] = _id.address().toInt(); tmp[1] = 0; - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); + //RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); _lastWroteState = now; } catch ( ... ) {} // sanity check, should not be possible @@ -522,22 +516,19 @@ bool Peer::applyStateUpdate(const void *data,unsigned int len) const uint64_t lastOut = b.at(ptr); ptr += 8; const uint64_t lastIn = b.at(ptr); ptr += 8; const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; - InetAddress addr,localAddr; + InetAddress addr; ptr += addr.deserialize(b,ptr); - ptr += localAddr.deserialize(b,ptr); - if (addr.ss_family == localAddr.ss_family) { - _PeerPath *p = (_PeerPath *)0; - switch(addr.ss_family) { - case AF_INET: p = &_v4Path; break; - case AF_INET6: p = &_v6Path; break; - } - if (p) { - if ( (!p->p) || ((p->p->address() != addr)||(p->p->localAddress() != localAddr)) ) { - p->p = RR->topology->getPath(localAddr,addr); - } - p->lr = lr; - p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); + _PeerPath *p = (_PeerPath *)0; + switch(addr.ss_family) { + case AF_INET: p = &_v4Path; break; + case AF_INET6: p = &_v6Path; break; + } + if (p) { + if ( (!p->p) || (p->p->address() != addr) ) { + p->p = RR->topology->getPath(-1,addr); } + p->lr = lr; + p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); } } } diff --git a/node/Peer.hpp b/node/Peer.hpp index f0eb3ee8..478c7232 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -154,12 +154,12 @@ public: * No statistics or sent times are updated here. * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local address + * @param localSocket Local source socket * @param atAddress Destination address * @param now Current time * @param counter Outgoing packet counter */ - void sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -167,13 +167,13 @@ public: * No statistics or sent times are updated here. * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local address + * @param localSocket Local source socket * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param counter Outgoing packet counter */ - void attemptToContactAt(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known @@ -227,11 +227,11 @@ public: { Mutex::Lock _l(_paths_m); if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); _v4Path.p->sent(now); _v4Path.lr = 0; // path will not be used unless it speaks again } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); _v6Path.p->sent(now); _v6Path.lr = 0; // path will not be used unless it speaks again } diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index ee0c8c24..99afe25d 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -67,6 +67,11 @@ public: Utils::burn(reinterpret_cast(const_cast(secretIdentityStr.data())),(unsigned int)secretIdentityStr.length()); } + /** + * A random integer identifying this running instance in a cluster + */ + uint64_t instanceId; + // Node instance that owns this RuntimeEnvironment Node *const node; @@ -90,11 +95,6 @@ public: Multicaster *mc; Topology *topology; SelfAwareness *sa; - - /** - * A random integer identifying this run of ZeroTier - */ - uint32_t instanceId; }; } // namespace ZeroTier diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index c5daddc3..3e3397f5 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -69,7 +69,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) +void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -77,7 +77,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const InetAddress &re return; Mutex::Lock _l(_phy_m); - PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalAddress,reporterPhysicalAddress,scope)]; + PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)]; if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 63c416bf..35e0ad39 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -55,7 +55,7 @@ public: * @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param now Current time */ - void iam(void *tPtr,const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); + void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); /** * Clean up database periodically @@ -75,15 +75,15 @@ private: struct PhySurfaceKey { Address reporter; - InetAddress receivedOnLocalAddress; + int64_t receivedOnLocalSocket; InetAddress reporterPhysicalAddress; InetAddress::IpScope scope; PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {} - PhySurfaceKey(const Address &r,const InetAddress &rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalAddress(rol),reporterPhysicalAddress(ra),scope(s) {} + PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {} - inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); } - inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(receivedOnLocalAddress == k.receivedOnLocalAddress)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } + inline unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)scope); } + inline bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } }; struct PhySurfaceEntry { diff --git a/node/Switch.cpp b/node/Switch.cpp index cbd73a83..a77ca89e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -71,12 +71,12 @@ Switch::Switch(const RuntimeEnvironment *renv) : { } -void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len) +void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len) { try { const uint64_t now = RR->node->now(); - SharedPtr path(RR->topology->getPath(localAddr,fromAddr)); + SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); if (len == 13) { @@ -88,7 +88,7 @@ void Switch::onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAd const Address beaconAddr(reinterpret_cast(data) + 8,5); if (beaconAddr == RR->identity.address()) return; - if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localAddr,fromAddr)) + if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr)) return; const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr)); if (peer) { // we'll only respond to beacons from known peers @@ -752,7 +752,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) viaPath = peer->getBestPath(now,false); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); + peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } viaPath.zero(); diff --git a/node/Switch.hpp b/node/Switch.hpp index 9793dd45..cebe9e67 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -68,12 +68,12 @@ public: * Called when a packet is received from the real network * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localAddr Local interface address + * @param localSocket Local I/O socket as supplied by external code * @param fromAddr Internet IP address of origin * @param data Packet data * @param len Packet length */ - void onRemotePacket(void *tPtr,const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len); + void onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len); /** * Called when a packet comes from a local Ethernet tap diff --git a/node/Topology.cpp b/node/Topology.cpp index 09a1a895..d4632f43 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -125,10 +125,11 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return *ap; } + /* try { char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; - int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER_STATE,idbuf,buf,(unsigned int)sizeof(buf)); + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf)); if (len > 0) { Mutex::Lock _l(_peers_m); SharedPtr &ap = _peers[zta]; @@ -140,6 +141,7 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return ap; } } catch ( ... ) {} // ignore invalid identities or other strage failures + */ return SharedPtr(); } diff --git a/node/Topology.hpp b/node/Topology.hpp index 32e38dd3..5f3e2da1 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -110,11 +110,11 @@ public: /** * Get a Path object for a given local and remote physical address, creating if needed * - * @param l Local address or NULL for 'any' or 'wildcard' + * @param l Local socket * @param r Remote address * @return Pointer to canonicalized Path object */ - inline SharedPtr getPath(const InetAddress &l,const InetAddress &r) + inline SharedPtr getPath(const int64_t l,const InetAddress &r) { Mutex::Lock _l(_paths_m); SharedPtr &p = _paths[Path::HashKey(l,r)]; diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index b1fe5921..040f3e46 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -88,11 +88,7 @@ class Binder : NonCopyable private: struct _Binding { - _Binding() : - udpSock((PhySocket *)0), - tcpListenSock((PhySocket *)0), - address() {} - + _Binding() : udpSock((PhySocket *)0),tcpListenSock((PhySocket *)0) {} PhySocket *udpSock; PhySocket *tcpListenSock; InetAddress address; @@ -373,93 +369,6 @@ public: _bindings.swap(newBindings); } - /** - * Send a UDP packet from the specified local interface, or all - * - * Unfortunately even by examining the routing table there is no ultimately - * robust way to tell where we might reach another host that works in all - * environments. As a result, we send packets with null (wildcard) local - * addresses from *every* bound interface. - * - * These are typically initial HELLOs, path probes, etc., since normal - * conversations will have a local endpoint address. So the cost is low and - * if the peer is not reachable via that route then the packet will go - * nowhere and nothing will happen. - * - * It will of course only send via interface bindings of the same socket - * family. No point in sending V4 via V6 or vice versa. - * - * In any case on most hosts there's only one or two interfaces that we - * will use, so none of this is particularly costly. - * - * @param local Local interface address or null address for 'all' - * @param remote Remote address - * @param data Data to send - * @param len Length of data - * @param v4ttl If non-zero, send this packet with the specified IP TTL (IPv4 only) - * @return -1 == local doesn't match any bound address, 0 == send failure, 1 == send successful - */ - template - inline int udpSend(Phy &phy,const InetAddress &local,const InetAddress &remote,const void *data,unsigned int len,unsigned int v4ttl = 0) const - { - PhySocket *s; - typename std::vector<_Binding>::const_iterator i; - int result; - Mutex::Lock _l(_lock); - - if (remote.ss_family == AF_INET) { - if (local) { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if ( - (i->address.ss_family == AF_INET) && - (reinterpret_cast(&(i->address))->sin_port == reinterpret_cast(&local)->sin_port) && - (reinterpret_cast(&(i->address))->sin_addr.s_addr == reinterpret_cast(&local)->sin_addr.s_addr) - ) - { - s = i->udpSock; - goto Binder_send_packet; - } - } - } else { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if (i->address.ss_family == AF_INET) { - s = i->udpSock; - goto Binder_send_packet; - } - } - } - } else { - if (local) { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if ( - (i->address.ss_family == AF_INET6) && - (reinterpret_cast(&(i->address))->sin6_port == reinterpret_cast(&local)->sin6_port) && - (!memcmp(reinterpret_cast(&(i->address))->sin6_addr.s6_addr,reinterpret_cast(&local)->sin6_addr.s6_addr,16)) - ) - { - s = i->udpSock; - goto Binder_send_packet; - } - } - } else { - for(i=_bindings.begin();i!=_bindings.end();++i) { - if (i->address.ss_family == AF_INET6) { - s = i->udpSock; - goto Binder_send_packet; - } - } - } - } - - return -1; - -Binder_send_packet: - if (v4ttl) phy.setIp4UdpTtl(s,v4ttl); - result = (int)phy.udpSend(s,reinterpret_cast(&remote),data,len); - if (v4ttl) phy.setIp4UdpTtl(s,255); - return result; - } - /** * @return All currently bound local interface addresses */ @@ -472,6 +381,22 @@ Binder_send_packet: return aa; } + /** + * Send from all bound UDP sockets + */ + template + inline bool udpSendAll(Phy &phy,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) + { + bool r = false; + Mutex::Lock _l(_lock); + for(std::vector<_Binding>::const_iterator b(_bindings.begin());b!=_bindings.end();++b) { + if (ttl) phy.setIp4UdpTtl(b->udpSock,ttl); + if (phy.udpSend(b->udpSock,(const struct sockaddr *)addr,data,len)) r = true; + if (ttl) phy.setIp4UdpTtl(b->udpSock,255); + } + return r; + } + /** * @param addr Address to check * @return True if this is a bound local interface address diff --git a/service/OneService.cpp b/service/OneService.cpp index b5b11111..6497ae20 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -59,8 +59,6 @@ #include "../osdep/ManagedRoute.hpp" #include "OneService.hpp" -#include "ClusterGeoIpService.hpp" -#include "ClusterDefinition.hpp" #include "SoftwareUpdater.hpp" #ifdef __WINDOWS__ @@ -157,9 +155,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } // Maximum write buffer size for outgoing TCP connections (sanity limit) #define ZT_TCP_MAX_WRITEQ_SIZE 33554432 -// How often to check TCP connections and cluster links and send status to cluster peers -#define ZT_TCP_CHECK_PERIOD 15000 - // TCP activity timeout #define ZT_TCP_ACTIVITY_TIMEOUT 60000 @@ -311,9 +306,9 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len); static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen); -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr); static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); @@ -362,8 +357,7 @@ struct TcpConnection TCP_UNCATEGORIZED_INCOMING, // uncategorized incoming connection TCP_HTTP_INCOMING, TCP_HTTP_OUTGOING, - TCP_TUNNEL_OUTGOING, // TUNNELED mode proxy outbound connection - TCP_CLUSTER_BACKPLANE + TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection } type; OneServiceImpl *parent; @@ -380,29 +374,11 @@ struct TcpConnection std::string status; std::map< std::string,std::string > headers; - // Used for cluster backplane connections - uint64_t clusterMemberId; - unsigned int clusterMemberVersionMajor; - unsigned int clusterMemberVersionMinor; - unsigned int clusterMemberVersionRev; - std::vector< InetAddress > clusterMemberLocalAddresses; - Mutex clusterMemberLocalAddresses_m; - std::string readq; std::string writeq; Mutex writeq_m; }; -/** - * Message types for cluster backplane communication - */ -enum ClusterMessageType -{ - CLUSTER_MESSAGE_STATUS = 0, - CLUSTER_MESSAGE_STATE_OBJECT = 1, - CLUSTER_MESSAGE_PROXY_SEND = 2 -}; - class OneServiceImpl : public OneService { public: @@ -421,8 +397,6 @@ public: bool _updateAutoApply; unsigned int _primaryPort; volatile unsigned int _udpPortPickerCounter; - uint64_t _clusterMemberId; - uint8_t _clusterKey[32]; // secret key for cluster backplane config // Local configuration and memo-ized information from it json _localConfig; @@ -434,7 +408,6 @@ public: std::vector< InetAddress > _globalV6Blacklist; std::vector< InetAddress > _allowManagementFrom; std::vector< std::string > _interfacePrefixBlacklist; - std::vector< InetAddress > _clusterBackplaneAddresses; Mutex _localConfig_m; /* @@ -518,7 +491,6 @@ public: ,_updateAutoApply(false) ,_primaryPort(port) ,_udpPortPickerCounter(0) - ,_clusterMemberId(0) ,_lastDirectReceiveFromGlobal(0) #ifdef ZT_TCP_FALLBACK_RELAY ,_lastSendToGlobalV4(0) @@ -754,23 +726,6 @@ public: } } - // Derive the cluster's shared secret backplane encryption key by hashing its shared secret identity - { - uint8_t tmp[64]; - uint8_t sk[ZT_C25519_PRIVATE_KEY_LEN + 4]; - memcpy(sk,_node->identity().privateKeyPair().priv.data,ZT_C25519_PRIVATE_KEY_LEN); - sk[ZT_C25519_PRIVATE_KEY_LEN] = 0xab; - sk[ZT_C25519_PRIVATE_KEY_LEN + 1] = 0xcd; - sk[ZT_C25519_PRIVATE_KEY_LEN + 2] = 0xef; - sk[ZT_C25519_PRIVATE_KEY_LEN + 3] = 0xab; // add an arbitrary nonce, just because - SHA512::hash(tmp,sk,ZT_C25519_PRIVATE_KEY_LEN + 4); - memcpy(_clusterKey,tmp,32); - } - - // Assign a random non-zero cluster member ID to identify vs. other cluster members - Utils::getSecureRandom(&_clusterMemberId,sizeof(_clusterMemberId)); - if (!_clusterMemberId) _clusterMemberId = 1; - // Main I/O loop _nextBackgroundTaskDeadline = 0; uint64_t clockShouldBe = OSUtils::now(); @@ -779,7 +734,6 @@ public: uint64_t lastBindRefresh = 0; uint64_t lastUpdateCheck = clockShouldBe; uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle - uint64_t lastTcpCheck = 0; for(;;) { _run_m.lock(); if (!_run) { @@ -873,58 +827,6 @@ public: _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); } - // Check TCP connections and cluster links - if ((now - lastTcpCheck) >= ZT_TCP_CHECK_PERIOD) { - lastTcpCheck = now; - - // Send status to active cluster links and close overflowed and dead ones - std::vector toClose; - std::vector clusterLinksUp; - { - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { - TcpConnection *const tc = *c; - tc->writeq_m.lock(); - const unsigned long wql = (unsigned long)tc->writeq.length(); - tc->writeq_m.unlock(); - if ((tc->sock)&&((wql > ZT_TCP_MAX_WRITEQ_SIZE)||((now - tc->lastReceive) > ZT_TCP_ACTIVITY_TIMEOUT))) { - toClose.push_back(tc->sock); - } else if ((tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(tc->clusterMemberId)) { - clusterLinksUp.push_back(tc->remoteAddr); - sendMyCurrentClusterState(tc); - } - } - } - for(std::vector::iterator s(toClose.begin());s!=toClose.end();++s) - _phy.close(*s,true); - - // Attempt to connect to cluster links we don't have an active connection to - { - Mutex::Lock _l(_localConfig_m); - for(std::vector::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) { - if ( (std::find(clusterLinksUp.begin(),clusterLinksUp.end(),*ca) == clusterLinksUp.end()) && (!_binder.isBoundLocalInterfaceAddress(*ca)) ) { - TcpConnection *tc = new TcpConnection(); - { - Mutex::Lock _l(_tcpConnections_m); - _tcpConnections.push_back(tc); - } - - tc->type = TcpConnection::TCP_CLUSTER_BACKPLANE; - tc->remoteAddr = *ca; - tc->lastReceive = OSUtils::now(); - tc->parent = this; - tc->sock = (PhySocket *)0; // set in connect handler - tc->messageSize = 0; - - tc->clusterMemberId = 0; // not known yet - - bool connected = false; - _phy.tcpConnect(reinterpret_cast(&(*ca)),connected,(void *)tc,true); - } - } - } - } - const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100; clockShouldBe = now + (uint64_t)delay; _phy.poll(delay); @@ -1211,21 +1113,6 @@ public: res["planetWorldId"] = planet.id(); res["planetWorldTimestamp"] = planet.timestamp(); - { - json cj(json::object()); - Mutex::Lock _l(_tcpConnections_m); - Mutex::Lock _l2(_localConfig_m); - for(std::vector::const_iterator ca(_clusterBackplaneAddresses.begin());ca!=_clusterBackplaneAddresses.end();++ca) { - uint64_t up = 0; - for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { - if (((*c)->remoteAddr == *ca)&&((*c)->clusterMemberId)&&((*c)->lastReceive > up)) - up = (*c)->lastReceive; - } - cj[ca->toString()] = up; - } - res["cluster"] = cj; - } - scode = 200; } else if (ps[0] == "moon") { std::vector moons(_node->moons()); @@ -1576,16 +1463,6 @@ public: } } - json &cl = settings["cluster"]; - _clusterBackplaneAddresses.clear(); - if (cl.is_array()) { - for(unsigned long i=0;i buf; - - buf.appendRandom(16); - buf.addSize(8); // space for MAC - buf.append((uint8_t)CLUSTER_MESSAGE_STATUS); - buf.append(_clusterMemberId); - buf.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR); - buf.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR); - buf.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - - std::vector lif(_binder.allBoundLocalInterfaceAddresses()); - buf.append((uint16_t)lif.size()); - for(std::vector::const_iterator i(lif.begin());i!=lif.end();++i) - i->serialize(buf); - - Mutex::Lock _l(tc->writeq_m); - - if (tc->writeq.length() == 0) - _phy.setNotifyWritable(tc->sock,true); - - const unsigned int mlen = buf.size(); - tc->writeq.push_back((char)((mlen >> 16) & 0xff)); - tc->writeq.push_back((char)((mlen >> 8) & 0xff)); - tc->writeq.push_back((char)(mlen & 0xff)); - - char *const data = reinterpret_cast(buf.unsafeData()); - encryptClusterMessage(data,mlen); - tc->writeq.append(data,mlen); - } catch ( ... ) { - fprintf(stderr,"WARNING: unexpected exception announcing status to cluster members" ZT_EOL_S); - } - } - - bool proxySendViaCluster(const InetAddress &fromAddress,const InetAddress &dest,const void *data,unsigned int len,unsigned int ttl) - { - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator c(_tcpConnections.begin());c!=_tcpConnections.end();++c) { - TcpConnection *const tc = *c; - if ((tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(tc->clusterMemberId)) { - Mutex::Lock _l2(tc->clusterMemberLocalAddresses_m); - for(std::vector::const_iterator i(tc->clusterMemberLocalAddresses.begin());i!=tc->clusterMemberLocalAddresses.end();++i) { - if (*i == fromAddress) { - Buffer<1024> buf; - - buf.appendRandom(16); - buf.addSize(8); // space for MAC - buf.append((uint8_t)CLUSTER_MESSAGE_PROXY_SEND); - buf.append((uint8_t)ttl); - dest.serialize(buf); - fromAddress.serialize(buf); - - Mutex::Lock _l3(tc->writeq_m); - - if (tc->writeq.length() == 0) - _phy.setNotifyWritable(tc->sock,true); - - const unsigned int mlen = buf.size() + len; - tc->writeq.push_back((char)((mlen >> 16) & 0xff)); - tc->writeq.push_back((char)((mlen >> 8) & 0xff)); - tc->writeq.push_back((char)(mlen & 0xff)); - - const unsigned long startpos = (unsigned long)tc->writeq.length(); - tc->writeq.append(reinterpret_cast(buf.data()),buf.size()); - tc->writeq.append(reinterpret_cast(data),len); - - char *const outdata = const_cast(tc->writeq.data()) + startpos; - encryptClusterMessage(outdata,mlen); - - return true; - } - } - } - } - return false; - } - - void replicateStateObject(const ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len,TcpConnection *tc) - { - char buf[42]; - Mutex::Lock _l2(tc->writeq_m); - - if (tc->writeq.length() == 0) - _phy.setNotifyWritable(tc->sock,true); - - const unsigned int mlen = len + 42; - - tc->writeq.push_back((char)((mlen >> 16) & 0xff)); - tc->writeq.push_back((char)((mlen >> 8) & 0xff)); - tc->writeq.push_back((char)(mlen & 0xff)); - - Utils::getSecureRandom(buf,16); - buf[24] = (char)CLUSTER_MESSAGE_STATE_OBJECT; - buf[25] = (char)type; - buf[26] = (char)((id[0] >> 56) & 0xff); - buf[27] = (char)((id[0] >> 48) & 0xff); - buf[28] = (char)((id[0] >> 40) & 0xff); - buf[29] = (char)((id[0] >> 32) & 0xff); - buf[30] = (char)((id[0] >> 24) & 0xff); - buf[31] = (char)((id[0] >> 16) & 0xff); - buf[32] = (char)((id[0] >> 8) & 0xff); - buf[33] = (char)(id[0] & 0xff); - buf[34] = (char)((id[1] >> 56) & 0xff); - buf[35] = (char)((id[1] >> 48) & 0xff); - buf[36] = (char)((id[1] >> 40) & 0xff); - buf[37] = (char)((id[1] >> 32) & 0xff); - buf[38] = (char)((id[1] >> 24) & 0xff); - buf[39] = (char)((id[1] >> 16) & 0xff); - buf[40] = (char)((id[1] >> 8) & 0xff); - buf[41] = (char)(id[1] & 0xff); - - const unsigned long startpos = (unsigned long)tc->writeq.length(); - tc->writeq.append(buf,42); - tc->writeq.append(reinterpret_cast(data),len); - - char *const outdata = const_cast(tc->writeq.data()) + startpos; - encryptClusterMessage(outdata,mlen); - tc->writeq.append(outdata,mlen); - } - - void writeStateObject(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) - { - char buf[65535]; - char p[1024]; - FILE *f; - bool secure = false; - - switch(type) { - case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_IDENTITY_SECRET: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); - secure = true; - break; - //case ZT_STATE_OBJECT_PEER_STATE: - // break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); - secure = true; - break; - //case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP: - // break; - case ZT_STATE_OBJECT_PLANET: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_MOON: - Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); - break; - default: - p[0] = (char)0; - break; - } - - if (p[0]) { - if (len >= 0) { - // Check to see if we've already written this first. This reduces - // redundant writes and I/O overhead on most platforms and has - // little effect on others. - f = fopen(p,"r"); - bool redundant = false; - if (f) { - long l = (long)fread(buf,1,sizeof(buf),f); - fclose(f); - redundant = ((l == (long)len)&&(memcmp(data,buf,l) == 0)); - } - if (!redundant) { - f = fopen(p,"w"); - if (f) { - if (fwrite(data,len,1,f) != 1) - fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); - fclose(f); - if (secure) - OSUtils::lockDownFile(p,false); - } else { - fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); - } - } - } else { - OSUtils::rm(p); - } - } - } - - void sendMyCurrentClusterState(TcpConnection *tc) - { - // We currently don't need to dump everything. Networks and moons are most important. - // The rest will get caught up rapidly due to constant peer updates, etc. - std::string buf; - std::vector l(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str(),false)); - for(std::vector::const_iterator f(l.begin());f!=l.end();++f) { - buf.clear(); - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { - if (f->length() == 21) { - const uint64_t nwid = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (nwid) { - uint64_t tmp[2]; - tmp[0] = nwid; - tmp[1] = 0; - replicateStateObject(ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,buf.data(),(int)buf.length(),tc); - } - } - } - } - l = OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "moons.d").c_str(),false); - for(std::vector::const_iterator f(l.begin());f!=l.end();++f) { - buf.clear(); - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S + *f).c_str(),buf)) { - if (f->length() == 21) { - const uint64_t moonId = Utils::hexStrToU64(f->substr(0,16).c_str()); - if (moonId) { - uint64_t tmp[2]; - tmp[0] = moonId; - tmp[1] = 0; - replicateStateObject(ZT_STATE_OBJECT_MOON,tmp,buf.data(),(int)buf.length(),tc); - } - } - } - } - } - // ========================================================================= // Handlers for Node and Phy<> callbacks // ========================================================================= @@ -2010,7 +1643,7 @@ public: const ZT_ResultCode rc = _node->processWirePacket( (void *)0, OSUtils::now(), - reinterpret_cast(localAddr), + (int64_t)((uintptr_t)sock), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big data, len, @@ -2044,13 +1677,6 @@ public: _phy.close(_tcpFallbackTunnel->sock); _tcpFallbackTunnel = tc; _phy.streamSend(sock,ZT_TCP_TUNNEL_HELLO,sizeof(ZT_TCP_TUNNEL_HELLO)); - } else if (tc->type == TcpConnection::TCP_CLUSTER_BACKPLANE) { - { - Mutex::Lock _l(tc->writeq_m); - tc->writeq.push_back((char)0x93); // identifies type of connection as cluster backplane - } - announceStatusToClusterMember(tc); - _phy.setNotifyWritable(sock,true); } else { _phy.close(sock,true); } @@ -2106,31 +1732,6 @@ public: case TcpConnection::TCP_UNCATEGORIZED_INCOMING: switch(reinterpret_cast(data)[0]) { - // 0x93 is first byte of cluster backplane connections - case 0x93: { - // We only allow this from cluster backplane IPs. We also authenticate - // each packet cryptographically, so this is just a first line of defense. - bool allow = false; - { - Mutex::Lock _l(_localConfig_m); - for(std::vector< InetAddress >::const_iterator i(_clusterBackplaneAddresses.begin());i!=_clusterBackplaneAddresses.end();++i) { - if (tc->remoteAddr.ipsEqual(*i)) { - allow = true; - break; - } - } - } - if (allow) { - tc->type = TcpConnection::TCP_CLUSTER_BACKPLANE; - tc->clusterMemberId = 0; // unknown, waiting for first status message - announceStatusToClusterMember(tc); - if (len > 1) - phyOnTcpData(sock,uptr,reinterpret_cast(data) + 1,len - 1); - } else { - _phy.close(sock); - } - } break; - // HTTP: GET, PUT, POST, HEAD case 'G': case 'P': @@ -2223,7 +1824,7 @@ public: const ZT_ResultCode rc = _node->processWirePacket( (void *)0, OSUtils::now(), - reinterpret_cast(&fakeTcpLocalInterfaceAddress), + -1, reinterpret_cast(&from), data, plen, @@ -2248,114 +1849,6 @@ public: } return; - case TcpConnection::TCP_CLUSTER_BACKPLANE: - tc->readq.append((const char *)data,len); - if (tc->readq.length() >= 28) { // got 3-byte message size + 16-byte IV + 8-byte MAC + 1-byte type (encrypted) - uint8_t *data = reinterpret_cast(const_cast(tc->readq.data())); - unsigned long mlen = ( ((unsigned long)data[0] << 16) | ((unsigned long)data[1] << 8) | (unsigned long)data[2] ); - if ((mlen < 25)||(mlen > ZT_TCP_MAX_WRITEQ_SIZE)) { - _phy.close(sock); - return; - } else if (tc->readq.length() >= (mlen + 3)) { // got entire message - data += 3; - - uint8_t key[32]; - memcpy(key,_clusterKey,32); - for(int i=0;i<8;++i) key[i] ^= data[i]; // first 8 bytes of IV get XORed with key - Salsa20 s20(key,data + 8); // last 8 bytes of IV are fed into Salsa20 directly as its 64-bit IV - - uint8_t macKey[32]; - uint8_t mac[16]; - memset(macKey,0,32); - s20.crypt12(macKey,macKey,32); - Poly1305::compute(mac,data + 24,mlen - 24,macKey); - if (!Utils::secureEq(mac,data + 16,8)) { - _phy.close(sock); - return; - } - s20.crypt12(data + 24,data + 24,mlen - 24); - - switch((ClusterMessageType)data[24]) { - case CLUSTER_MESSAGE_STATUS: - if (mlen > (25 + 16)) { - Buffer<4096> tmp(data + 25,mlen - 25); - try { - const uint64_t cmid = tmp.at(0); - if (cmid == _clusterMemberId) { // shouldn't happen, but don't allow self-to-self - _phy.close(sock); - return; - } - if (!tc->clusterMemberId) { - tc->clusterMemberId = cmid; - sendMyCurrentClusterState(tc); - } - tc->clusterMemberVersionMajor = tmp.at(8); - tc->clusterMemberVersionMinor = tmp.at(10); - tc->clusterMemberVersionRev = tmp.at(12); - const unsigned int clusterMemberLocalAddressCount = tmp.at(14); - std::vector la; - unsigned int ptr = 16; - for(unsigned int k=0;kclusterMemberLocalAddresses_m); - tc->clusterMemberLocalAddresses.swap(la); - } - } catch ( ... ) {} - } - break; - - case CLUSTER_MESSAGE_STATE_OBJECT: - if (mlen > 42) { // type + object ID + [data] - uint64_t objId[2]; - objId[0] = ( - ((uint64_t)data[26] << 56) | - ((uint64_t)data[27] << 48) | - ((uint64_t)data[28] << 40) | - ((uint64_t)data[29] << 32) | - ((uint64_t)data[30] << 24) | - ((uint64_t)data[31] << 16) | - ((uint64_t)data[32] << 8) | - (uint64_t)data[33] - ); - objId[1] = ( - ((uint64_t)data[34] << 56) | - ((uint64_t)data[35] << 48) | - ((uint64_t)data[36] << 40) | - ((uint64_t)data[37] << 32) | - ((uint64_t)data[38] << 24) | - ((uint64_t)data[39] << 16) | - ((uint64_t)data[40] << 8) | - (uint64_t)data[41] - ); - if (_node->processStateUpdate((void *)0,(ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)) == ZT_RESULT_OK) - writeStateObject((ZT_StateObjectType)data[25],objId,data + 42,(unsigned int)(mlen - 42)); - } - break; - - case CLUSTER_MESSAGE_PROXY_SEND: - if (mlen > 25) { - Buffer<4096> tmp(data + 25,mlen - 25); - try { - InetAddress dest,src; - const unsigned int ttl = (unsigned int)tmp[0]; - unsigned int ptr = 1; - ptr += dest.deserialize(tmp); - ptr += src.deserialize(tmp,ptr); - if (ptr < tmp.size()) - _binder.udpSend(_phy,src,dest,reinterpret_cast(tmp.data()) + ptr,tmp.size() - ptr,ttl); - } catch ( ... ) {} - } - break; - } - - tc->readq.erase(tc->readq.begin(),tc->readq.begin() + mlen); - } - } - return; - } } catch ( ... ) { _phy.close(sock); @@ -2549,18 +2042,57 @@ public: inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { - writeStateObject(type,id,data,len); + char p[1024]; + FILE *f; + bool secure = false; - std::vector sentTo; - { - Mutex::Lock _l(_tcpConnections_m); - for(std::vector::const_iterator ci(_tcpConnections.begin());ci!=_tcpConnections.end();++ci) { - TcpConnection *const c = *ci; - if ((c->type == TcpConnection::TCP_CLUSTER_BACKPLANE)&&(c->clusterMemberId != 0)&&(std::find(sentTo.begin(),sentTo.end(),c->clusterMemberId) == sentTo.end())) { - sentTo.push_back(c->clusterMemberId); - replicateStateObject(type,id,data,len,c); - } + switch(type) { + case ZT_STATE_OBJECT_IDENTITY_PUBLIC: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_IDENTITY_SECRET: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + secure = true; + break; + case ZT_STATE_OBJECT_PLANET: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_MOON: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + Utils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + secure = true; + break; + default: + return; + } + + if (len >= 0) { + // Check to see if we've already written this first. This reduces + // redundant writes and I/O overhead on most platforms and has + // little effect on others. + f = fopen(p,"r"); + if (f) { + char buf[65535]; + long l = (long)fread(buf,1,sizeof(buf),f); + fclose(f); + if ((l == (long)len)&&(memcmp(data,buf,l) == 0)) + return; } + + f = fopen(p,"w"); + if (f) { + if (fwrite(data,len,1,f) != 1) + fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + fclose(f); + if (secure) + OSUtils::lockDownFile(p,false); + } else { + fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + } + } else { + OSUtils::rm(p); } } @@ -2596,7 +2128,7 @@ public: return -1; } - inline int nodeWirePacketSendFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) + inline int nodeWirePacketSendFunction(const int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) { #ifdef ZT_TCP_FALLBACK_RELAY if (addr->ss_family == AF_INET) { @@ -2646,20 +2178,13 @@ public: // proxy fallback, which is slow. #endif // ZT_TCP_FALLBACK_RELAY - switch (_binder.udpSend(_phy,*(reinterpret_cast(localAddr)),*(reinterpret_cast(addr)),data,len,ttl)) { - case -1: // local bound address not found, so see if a cluster peer owns it - if (localAddr->ss_family != 0) { - return (proxySendViaCluster(*(reinterpret_cast(localAddr)),*(reinterpret_cast(addr)),data,len,ttl)) ? 0 : -1; - } else { - return -1; // failure - } - break; - - case 0: // failure - return -1; - - default: // success - return 0; + if ((localSocket != 0)&&(localSocket != -1)) { + if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),ttl); + const bool r = _phy.udpSend((PhySocket *)((uintptr_t)localSocket),(const struct sockaddr *)addr,data,len); + if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),255); + return ((r) ? 0 : -1); + } else { + return ((_binder.udpSendAll(_phy,addr,data,len,ttl)) ? 0 : -1); } } @@ -2671,7 +2196,7 @@ public: n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); } - inline int nodePathCheckFunction(uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) + inline int nodePathCheckFunction(uint64_t ztaddr,const int64_t localSocket,const struct sockaddr_storage *remoteAddr) { // Make sure we're not trying to do ZeroTier-over-ZeroTier { @@ -2882,12 +2407,12 @@ static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_St { reinterpret_cast(uptr)->nodeStatePutFunction(type,id,data,len); } static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { return reinterpret_cast(uptr)->nodeStateGetFunction(type,id,data,maxlen); } -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) -{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); } +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) +{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); } static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) { reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localAddr,remoteAddr); } +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr) +{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); } static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) { return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -- cgit v1.2.3 From 640ad577d1f52140adbe42e87b2da931bf15f430 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 11:56:46 -0700 Subject: . --- attic/ClusterGeoIpService.cpp | 243 ++++++++++++++++++++++++++++++++++++++++ attic/ClusterGeoIpService.hpp | 151 +++++++++++++++++++++++++ make-bsd.mk | 5 - make-linux.mk | 4 - make-mac.mk | 4 - node/Constants.hpp | 5 - node/Path.hpp | 12 -- node/Peer.cpp | 157 -------------------------- node/Peer.hpp | 31 ----- node/Topology.cpp | 5 +- objects.mk | 1 - service/ClusterGeoIpService.cpp | 243 ---------------------------------------- service/ClusterGeoIpService.hpp | 151 ------------------------- 13 files changed, 395 insertions(+), 617 deletions(-) create mode 100644 attic/ClusterGeoIpService.cpp create mode 100644 attic/ClusterGeoIpService.hpp delete mode 100644 service/ClusterGeoIpService.cpp delete mode 100644 service/ClusterGeoIpService.hpp (limited to 'node/Peer.cpp') diff --git a/attic/ClusterGeoIpService.cpp b/attic/ClusterGeoIpService.cpp new file mode 100644 index 00000000..2dcc9179 --- /dev/null +++ b/attic/ClusterGeoIpService.cpp @@ -0,0 +1,243 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifdef ZT_ENABLE_CLUSTER + +#include + +#include + +#include "ClusterGeoIpService.hpp" + +#include "../node/Utils.hpp" +#include "../osdep/OSUtils.hpp" + +#define ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY 10000 + +namespace ZeroTier { + +ClusterGeoIpService::ClusterGeoIpService() : + _pathToCsv(), + _ipStartColumn(-1), + _ipEndColumn(-1), + _latitudeColumn(-1), + _longitudeColumn(-1), + _lastFileCheckTime(0), + _csvModificationTime(0), + _csvFileSize(0) +{ +} + +ClusterGeoIpService::~ClusterGeoIpService() +{ +} + +bool ClusterGeoIpService::locate(const InetAddress &ip,int &x,int &y,int &z) +{ + Mutex::Lock _l(_lock); + + if ((_pathToCsv.length() > 0)&&((OSUtils::now() - _lastFileCheckTime) > ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY)) { + _lastFileCheckTime = OSUtils::now(); + if ((_csvFileSize != OSUtils::getFileSize(_pathToCsv.c_str()))||(_csvModificationTime != OSUtils::getLastModified(_pathToCsv.c_str()))) + _load(_pathToCsv.c_str(),_ipStartColumn,_ipEndColumn,_latitudeColumn,_longitudeColumn); + } + + /* We search by looking up the upper bound of the sorted vXdb vectors + * and then iterating down for a matching IP range. We stop when we hit + * the beginning or an entry whose start and end are before the IP we + * are searching. */ + + if ((ip.ss_family == AF_INET)&&(_v4db.size() > 0)) { + _V4E key; + key.start = Utils::ntoh((uint32_t)(reinterpret_cast(&ip)->sin_addr.s_addr)); + std::vector<_V4E>::const_iterator i(std::upper_bound(_v4db.begin(),_v4db.end(),key)); + while (i != _v4db.begin()) { + --i; + if ((key.start >= i->start)&&(key.start <= i->end)) { + x = i->x; + y = i->y; + z = i->z; + //printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z); + return true; + } else if ((key.start > i->start)&&(key.start > i->end)) + break; + } + } else if ((ip.ss_family == AF_INET6)&&(_v6db.size() > 0)) { + _V6E key; + memcpy(key.start,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); + std::vector<_V6E>::const_iterator i(std::upper_bound(_v6db.begin(),_v6db.end(),key)); + while (i != _v6db.begin()) { + --i; + const int s_vs_s = memcmp(key.start,i->start,16); + const int s_vs_e = memcmp(key.start,i->end,16); + if ((s_vs_s >= 0)&&(s_vs_e <= 0)) { + x = i->x; + y = i->y; + z = i->z; + //printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z); + return true; + } else if ((s_vs_s > 0)&&(s_vs_e > 0)) + break; + } + } + + return false; +} + +void ClusterGeoIpService::_parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) +{ + std::vector ls(OSUtils::split(line,",\t","\\","\"'")); + if ( ((ipStartColumn >= 0)&&(ipStartColumn < (int)ls.size()))&& + ((ipEndColumn >= 0)&&(ipEndColumn < (int)ls.size()))&& + ((latitudeColumn >= 0)&&(latitudeColumn < (int)ls.size()))&& + ((longitudeColumn >= 0)&&(longitudeColumn < (int)ls.size())) ) { + InetAddress ipStart(ls[ipStartColumn].c_str(),0); + InetAddress ipEnd(ls[ipEndColumn].c_str(),0); + const double lat = strtod(ls[latitudeColumn].c_str(),(char **)0); + const double lon = strtod(ls[longitudeColumn].c_str(),(char **)0); + + if ((ipStart.ss_family == ipEnd.ss_family)&&(ipStart)&&(ipEnd)&&(std::isfinite(lat))&&(std::isfinite(lon))) { + const double latRadians = lat * 0.01745329251994; // PI / 180 + const double lonRadians = lon * 0.01745329251994; // PI / 180 + const double cosLat = cos(latRadians); + const int x = (int)round((-6371.0) * cosLat * cos(lonRadians)); // 6371 == Earth's approximate radius in kilometers + const int y = (int)round(6371.0 * sin(latRadians)); + const int z = (int)round(6371.0 * cosLat * sin(lonRadians)); + + if (ipStart.ss_family == AF_INET) { + v4db.push_back(_V4E()); + v4db.back().start = Utils::ntoh((uint32_t)(reinterpret_cast(&ipStart)->sin_addr.s_addr)); + v4db.back().end = Utils::ntoh((uint32_t)(reinterpret_cast(&ipEnd)->sin_addr.s_addr)); + v4db.back().lat = (float)lat; + v4db.back().lon = (float)lon; + v4db.back().x = x; + v4db.back().y = y; + v4db.back().z = z; + //printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z); + } else if (ipStart.ss_family == AF_INET6) { + v6db.push_back(_V6E()); + memcpy(v6db.back().start,reinterpret_cast(&ipStart)->sin6_addr.s6_addr,16); + memcpy(v6db.back().end,reinterpret_cast(&ipEnd)->sin6_addr.s6_addr,16); + v6db.back().lat = (float)lat; + v6db.back().lon = (float)lon; + v6db.back().x = x; + v6db.back().y = y; + v6db.back().z = z; + //printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z); + } + } + } +} + +long ClusterGeoIpService::_load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) +{ + // assumes _lock is locked + + FILE *f = fopen(pathToCsv,"rb"); + if (!f) + return -1; + + std::vector<_V4E> v4db; + std::vector<_V6E> v6db; + v4db.reserve(16777216); + v6db.reserve(16777216); + + char buf[4096]; + char linebuf[1024]; + unsigned int lineptr = 0; + for(;;) { + int n = (int)fread(buf,1,sizeof(buf),f); + if (n <= 0) + break; + for(int i=0;i 0)||(v6db.size() > 0)) { + std::sort(v4db.begin(),v4db.end()); + std::sort(v6db.begin(),v6db.end()); + + _pathToCsv = pathToCsv; + _ipStartColumn = ipStartColumn; + _ipEndColumn = ipEndColumn; + _latitudeColumn = latitudeColumn; + _longitudeColumn = longitudeColumn; + + _lastFileCheckTime = OSUtils::now(); + _csvModificationTime = OSUtils::getLastModified(pathToCsv); + _csvFileSize = OSUtils::getFileSize(pathToCsv); + + _v4db.swap(v4db); + _v6db.swap(v6db); + + return (long)(_v4db.size() + _v6db.size()); + } else { + return 0; + } +} + +} // namespace ZeroTier + +#endif // ZT_ENABLE_CLUSTER + +/* +int main(int argc,char **argv) +{ + char buf[1024]; + + ZeroTier::ClusterGeoIpService gip; + printf("loading...\n"); + gip.load("/Users/api/Code/ZeroTier/Infrastructure/root-servers/zerotier-one/cluster-geoip.csv",0,1,5,6); + printf("... done!\n"); fflush(stdout); + + while (gets(buf)) { // unsafe, testing only + ZeroTier::InetAddress addr(buf,0); + printf("looking up: %s\n",addr.toString().c_str()); fflush(stdout); + int x = 0,y = 0,z = 0; + if (gip.locate(addr,x,y,z)) { + //printf("%s: %d,%d,%d\n",addr.toString().c_str(),x,y,z); fflush(stdout); + } else { + printf("%s: not found!\n",addr.toString().c_str()); fflush(stdout); + } + } + + return 0; +} +*/ diff --git a/attic/ClusterGeoIpService.hpp b/attic/ClusterGeoIpService.hpp new file mode 100644 index 00000000..380f944f --- /dev/null +++ b/attic/ClusterGeoIpService.hpp @@ -0,0 +1,151 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_CLUSTERGEOIPSERVICE_HPP +#define ZT_CLUSTERGEOIPSERVICE_HPP + +#ifdef ZT_ENABLE_CLUSTER + +#include +#include +#include +#include + +#include +#include +#include + +#include "../node/Constants.hpp" +#include "../node/Mutex.hpp" +#include "../node/NonCopyable.hpp" +#include "../node/InetAddress.hpp" + +namespace ZeroTier { + +/** + * Loads a GeoIP CSV into memory for fast lookup, reloading as needed + * + * This was designed around the CSV from https://db-ip.com but can be used + * with any similar GeoIP CSV database that is presented in the form of an + * IP range and lat/long coordinates. + * + * It loads the whole database into memory, which can be kind of large. If + * the CSV file changes, the changes are loaded automatically. + */ +class ClusterGeoIpService : NonCopyable +{ +public: + ClusterGeoIpService(); + ~ClusterGeoIpService(); + + /** + * Load or reload CSV file + * + * CSV column indexes start at zero. CSVs can be quoted with single or + * double quotes. Whitespace before or after commas is ignored. Backslash + * may be used for escaping whitespace as well. + * + * @param pathToCsv Path to (uncompressed) CSV file + * @param ipStartColumn Column with IP range start + * @param ipEndColumn Column with IP range end (inclusive) + * @param latitudeColumn Column with latitude + * @param longitudeColumn Column with longitude + * @return Number of valid records loaded or -1 on error (invalid file, not found, etc.) + */ + inline long load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) + { + Mutex::Lock _l(_lock); + return _load(pathToCsv,ipStartColumn,ipEndColumn,latitudeColumn,longitudeColumn); + } + + /** + * Attempt to locate an IP + * + * This returns true if x, y, and z are set. If the return value is false + * the values of x, y, and z are undefined. + * + * @param ip IPv4 or IPv6 address + * @param x Reference to variable to receive X + * @param y Reference to variable to receive Y + * @param z Reference to variable to receive Z + * @return True if coordinates were set + */ + bool locate(const InetAddress &ip,int &x,int &y,int &z); + + /** + * @return True if IP database/service is available for queries (otherwise locate() will always be false) + */ + inline bool available() const + { + Mutex::Lock _l(_lock); + return ((_v4db.size() + _v6db.size()) > 0); + } + +private: + struct _V4E + { + uint32_t start; + uint32_t end; + float lat,lon; + int16_t x,y,z; + + inline bool operator<(const _V4E &e) const { return (start < e.start); } + }; + + struct _V6E + { + uint8_t start[16]; + uint8_t end[16]; + float lat,lon; + int16_t x,y,z; + + inline bool operator<(const _V6E &e) const { return (memcmp(start,e.start,16) < 0); } + }; + + static void _parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn); + long _load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn); + + std::string _pathToCsv; + int _ipStartColumn; + int _ipEndColumn; + int _latitudeColumn; + int _longitudeColumn; + + uint64_t _lastFileCheckTime; + uint64_t _csvModificationTime; + int64_t _csvFileSize; + + std::vector<_V4E> _v4db; + std::vector<_V6E> _v6db; + + Mutex _lock; +}; + +} // namespace ZeroTier + +#endif // ZT_ENABLE_CLUSTER + +#endif diff --git a/make-bsd.mk b/make-bsd.mk index cbab5810..c2fd6062 100644 --- a/make-bsd.mk +++ b/make-bsd.mk @@ -7,11 +7,6 @@ LIBS= include objects.mk ONE_OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o -# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - # "make debug" is a shortcut for this ifeq ($(ZT_DEBUG),1) CFLAGS+=-Wall -Werror -g -pthread $(INCLUDES) $(DEFS) diff --git a/make-linux.mk b/make-linux.mk index c27c600d..7017d31e 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -38,10 +38,6 @@ endif # Trying to use dynamically linked libhttp-parser causes tons of compatibility problems. ONE_OBJS+=ext/http-parser/http_parser.o -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - ifeq ($(ZT_SYNOLOGY), 1) DEFS+=-D__SYNOLOGY__ endif diff --git a/make-mac.mk b/make-mac.mk index 5622a41b..196b17cb 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -33,10 +33,6 @@ else DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"download\"" endif -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - # Use fast ASM Salsa20/12 for x64 processors DEFS+=-DZT_USE_X64_ASM_SALSA2012 CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o diff --git a/node/Constants.hpp b/node/Constants.hpp index 274b9564..12bf8d28 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -218,11 +218,6 @@ */ #define ZT_HOUSEKEEPING_PERIOD 60000 -/** - * How often in ms to write peer state to storage and/or cluster (approximate) - */ -#define ZT_PEER_STATE_WRITE_PERIOD 10000 - /** * How long to remember peer records in RAM if they haven't been used */ diff --git a/node/Path.hpp b/node/Path.hpp index 854b28e2..ac8e4c0e 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -283,18 +283,6 @@ public: */ inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } - /** - * @param lo Last out send - * @param li Last in send - * @param lt Last trust established packet received - */ - inline void updateFromRemoteState(const uint64_t lo,const uint64_t li,const uint64_t lt) - { - _lastOut = lo; - _lastIn = li; - _lastTrustEstablishedPacketReceived = lt; - } - /** * Return and increment outgoing packet counter (used with Packet::armor()) * diff --git a/node/Peer.cpp b/node/Peer.cpp index 875d651e..fb9a72b1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -38,8 +38,6 @@ namespace ZeroTier { Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) : RR(renv), - _lastWroteState(0), - _lastReceivedStateTimestamp(0), _lastReceive(0), _lastNontrivialReceive(0), _lastTriedMemorizedPath(0), @@ -184,7 +182,6 @@ void Peer::received( if (verb == Packet::VERB_OK) { potentialNewPeerPath->lr = now; potentialNewPeerPath->p = path; - _lastWroteState = 0; // force state write now } else { TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); @@ -263,9 +260,6 @@ void Peer::received( } } } - - if ((now - _lastWroteState) > ZT_PEER_STATE_WRITE_PERIOD) - writeState(tPtr,now); } bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) @@ -428,155 +422,4 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } -void Peer::writeState(void *tPtr,const uint64_t now) -{ - try { - Buffer b; - - b.append((uint8_t)1); // version - b.append(now); - - _id.serialize(b); - - { - Mutex::Lock _l(_paths_m); - unsigned int count = 0; - if (_v4Path.lr) - ++count; - if (_v6Path.lr) - ++count; - b.append((uint8_t)count); - if (_v4Path.lr) { - b.append(_v4Path.lr); - b.append(_v4Path.p->lastOut()); - b.append(_v4Path.p->lastIn()); - b.append(_v4Path.p->lastTrustEstablishedPacketReceived()); - _v4Path.p->address().serialize(b); - } - if (_v6Path.lr) { - b.append(_v6Path.lr); - b.append(_v6Path.p->lastOut()); - b.append(_v6Path.p->lastIn()); - b.append(_v6Path.p->lastTrustEstablishedPacketReceived()); - _v6Path.p->address().serialize(b); - } - } - - // Save space by sending these as time since now at 100ms resolution - b.append((uint16_t)(std::max(now - _lastReceive,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastNontrivialReceive,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastTriedMemorizedPath,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastDirectPathPushSent,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastDirectPathPushReceive,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastCredentialRequestSent,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastWhoisRequestReceived,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastEchoRequestReceived,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastComRequestReceived,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastComRequestSent,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastCredentialsReceived,(uint64_t)6553500) / 100)); - b.append((uint16_t)(std::max(now - _lastTrustEstablishedPacketReceived,(uint64_t)6553500) / 100)); - - b.append((uint8_t)_vProto); - b.append((uint8_t)_vMajor); - b.append((uint8_t)_vMinor); - b.append((uint16_t)_vRevision); - - b.append((uint16_t)0); // length of additional fields - - uint64_t tmp[2]; - tmp[0] = _id.address().toInt(); tmp[1] = 0; - //RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER_STATE,tmp,b.data(),b.size()); - - _lastWroteState = now; - } catch ( ... ) {} // sanity check, should not be possible -} - -bool Peer::applyStateUpdate(const void *data,unsigned int len) -{ - try { - Buffer b(data,len); - unsigned int ptr = 0; - - if (b[ptr++] != 1) - return false; - const uint64_t ts = b.at(ptr); ptr += 8; - if (ts <= _lastReceivedStateTimestamp) - return false; - - Identity id; - ptr += id.deserialize(b,ptr); - if (id != _id) // sanity check - return false; - - const unsigned int pathCount = (unsigned int)b[ptr++]; - { - Mutex::Lock _l(_paths_m); - for(unsigned int i=0;i(ptr); ptr += 8; - const uint64_t lastOut = b.at(ptr); ptr += 8; - const uint64_t lastIn = b.at(ptr); ptr += 8; - const uint64_t lastTrustEstablishedPacketReceived = b.at(ptr); ptr += 8; - InetAddress addr; - ptr += addr.deserialize(b,ptr); - _PeerPath *p = (_PeerPath *)0; - switch(addr.ss_family) { - case AF_INET: p = &_v4Path; break; - case AF_INET6: p = &_v6Path; break; - } - if (p) { - if ( (!p->p) || (p->p->address() != addr) ) { - p->p = RR->topology->getPath(-1,addr); - } - p->lr = lr; - p->p->updateFromRemoteState(lastOut,lastIn,lastTrustEstablishedPacketReceived); - } - } - } - - _lastReceive = std::max(_lastReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastNontrivialReceive = std::max(_lastNontrivialReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastTriedMemorizedPath = std::max(_lastTriedMemorizedPath,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastDirectPathPushSent = std::max(_lastDirectPathPushSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastDirectPathPushReceive = std::max(_lastDirectPathPushReceive,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastCredentialRequestSent = std::max(_lastCredentialRequestSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastWhoisRequestReceived = std::max(_lastWhoisRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastEchoRequestReceived = std::max(_lastEchoRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastComRequestReceived = std::max(_lastComRequestReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastComRequestSent = std::max(_lastComRequestSent,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastCredentialsReceived = std::max(_lastCredentialsReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - _lastTrustEstablishedPacketReceived = std::max(_lastTrustEstablishedPacketReceived,ts - ((uint64_t)b.at(ptr) * 100ULL)); ptr += 2; - - _vProto = (uint16_t)b[ptr++]; - _vMajor = (uint16_t)b[ptr++]; - _vMinor = (uint16_t)b[ptr++]; - _vRevision = b.at(ptr); ptr += 2; - - _lastReceivedStateTimestamp = ts; - - return true; - } catch ( ... ) {} // ignore invalid state updates - return false; -} - -SharedPtr Peer::createFromStateUpdate(const RuntimeEnvironment *renv,void *tPtr,const void *data,unsigned int len) -{ - try { - Identity id; - { - Buffer b(data,len); - unsigned int ptr = 0; - if (b[ptr++] != 1) - return SharedPtr(); - ptr += 8; // skip TS, don't care - id.deserialize(b,ptr); - } - if (id) { - const SharedPtr p(new Peer(renv,renv->identity,id)); - if (p->applyStateUpdate(data,len)) - return renv->topology->addPeer(tPtr,p); - } - } catch ( ... ) {} - return SharedPtr(); -} - } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 478c7232..ad2d0ddc 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -195,23 +195,6 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); - /** - * Write object state to external storage and/or cluster network - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - void writeState(void *tPtr,const uint64_t now); - - /** - * Apply a state update received from e.g. a remote cluster member - * - * @param data State update data - * @param len Length of state update - * @return True if state update was applied, false if ignored or invalid - */ - bool applyStateUpdate(const void *data,unsigned int len); - /** * Reset paths within a given IP scope and address family * @@ -440,17 +423,6 @@ public: return false; } - /** - * Create a peer from a remote state update - * - * @param renv Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param data State update data - * @param len State update length - * @return Peer or NULL if data was invalid - */ - static SharedPtr createFromStateUpdate(const RuntimeEnvironment *renv,void *tPtr,const void *data,unsigned int len); - private: struct _PeerPath { @@ -463,9 +435,6 @@ private: const RuntimeEnvironment *RR; - uint64_t _lastWroteState; - uint64_t _lastReceivedStateTimestamp; - uint64_t _lastReceive; // direct or indirect uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. uint64_t _lastTriedMemorizedPath; diff --git a/node/Topology.cpp b/node/Topology.cpp index d4632f43..809bc7e7 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -395,11 +395,8 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) _peers.erase(*a); - } else { - (*p)->writeState(tPtr,now); - } } } diff --git a/objects.mk b/objects.mk index c8231f08..3a8bd645 100644 --- a/objects.mk +++ b/objects.mk @@ -31,7 +31,6 @@ ONE_OBJS=\ osdep/ManagedRoute.o \ osdep/Http.o \ osdep/OSUtils.o \ - service/ClusterGeoIpService.o \ service/SoftwareUpdater.o \ service/OneService.o diff --git a/service/ClusterGeoIpService.cpp b/service/ClusterGeoIpService.cpp deleted file mode 100644 index 2dcc9179..00000000 --- a/service/ClusterGeoIpService.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 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 . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. - */ - -#ifdef ZT_ENABLE_CLUSTER - -#include - -#include - -#include "ClusterGeoIpService.hpp" - -#include "../node/Utils.hpp" -#include "../osdep/OSUtils.hpp" - -#define ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY 10000 - -namespace ZeroTier { - -ClusterGeoIpService::ClusterGeoIpService() : - _pathToCsv(), - _ipStartColumn(-1), - _ipEndColumn(-1), - _latitudeColumn(-1), - _longitudeColumn(-1), - _lastFileCheckTime(0), - _csvModificationTime(0), - _csvFileSize(0) -{ -} - -ClusterGeoIpService::~ClusterGeoIpService() -{ -} - -bool ClusterGeoIpService::locate(const InetAddress &ip,int &x,int &y,int &z) -{ - Mutex::Lock _l(_lock); - - if ((_pathToCsv.length() > 0)&&((OSUtils::now() - _lastFileCheckTime) > ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY)) { - _lastFileCheckTime = OSUtils::now(); - if ((_csvFileSize != OSUtils::getFileSize(_pathToCsv.c_str()))||(_csvModificationTime != OSUtils::getLastModified(_pathToCsv.c_str()))) - _load(_pathToCsv.c_str(),_ipStartColumn,_ipEndColumn,_latitudeColumn,_longitudeColumn); - } - - /* We search by looking up the upper bound of the sorted vXdb vectors - * and then iterating down for a matching IP range. We stop when we hit - * the beginning or an entry whose start and end are before the IP we - * are searching. */ - - if ((ip.ss_family == AF_INET)&&(_v4db.size() > 0)) { - _V4E key; - key.start = Utils::ntoh((uint32_t)(reinterpret_cast(&ip)->sin_addr.s_addr)); - std::vector<_V4E>::const_iterator i(std::upper_bound(_v4db.begin(),_v4db.end(),key)); - while (i != _v4db.begin()) { - --i; - if ((key.start >= i->start)&&(key.start <= i->end)) { - x = i->x; - y = i->y; - z = i->z; - //printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z); - return true; - } else if ((key.start > i->start)&&(key.start > i->end)) - break; - } - } else if ((ip.ss_family == AF_INET6)&&(_v6db.size() > 0)) { - _V6E key; - memcpy(key.start,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - std::vector<_V6E>::const_iterator i(std::upper_bound(_v6db.begin(),_v6db.end(),key)); - while (i != _v6db.begin()) { - --i; - const int s_vs_s = memcmp(key.start,i->start,16); - const int s_vs_e = memcmp(key.start,i->end,16); - if ((s_vs_s >= 0)&&(s_vs_e <= 0)) { - x = i->x; - y = i->y; - z = i->z; - //printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z); - return true; - } else if ((s_vs_s > 0)&&(s_vs_e > 0)) - break; - } - } - - return false; -} - -void ClusterGeoIpService::_parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) -{ - std::vector ls(OSUtils::split(line,",\t","\\","\"'")); - if ( ((ipStartColumn >= 0)&&(ipStartColumn < (int)ls.size()))&& - ((ipEndColumn >= 0)&&(ipEndColumn < (int)ls.size()))&& - ((latitudeColumn >= 0)&&(latitudeColumn < (int)ls.size()))&& - ((longitudeColumn >= 0)&&(longitudeColumn < (int)ls.size())) ) { - InetAddress ipStart(ls[ipStartColumn].c_str(),0); - InetAddress ipEnd(ls[ipEndColumn].c_str(),0); - const double lat = strtod(ls[latitudeColumn].c_str(),(char **)0); - const double lon = strtod(ls[longitudeColumn].c_str(),(char **)0); - - if ((ipStart.ss_family == ipEnd.ss_family)&&(ipStart)&&(ipEnd)&&(std::isfinite(lat))&&(std::isfinite(lon))) { - const double latRadians = lat * 0.01745329251994; // PI / 180 - const double lonRadians = lon * 0.01745329251994; // PI / 180 - const double cosLat = cos(latRadians); - const int x = (int)round((-6371.0) * cosLat * cos(lonRadians)); // 6371 == Earth's approximate radius in kilometers - const int y = (int)round(6371.0 * sin(latRadians)); - const int z = (int)round(6371.0 * cosLat * sin(lonRadians)); - - if (ipStart.ss_family == AF_INET) { - v4db.push_back(_V4E()); - v4db.back().start = Utils::ntoh((uint32_t)(reinterpret_cast(&ipStart)->sin_addr.s_addr)); - v4db.back().end = Utils::ntoh((uint32_t)(reinterpret_cast(&ipEnd)->sin_addr.s_addr)); - v4db.back().lat = (float)lat; - v4db.back().lon = (float)lon; - v4db.back().x = x; - v4db.back().y = y; - v4db.back().z = z; - //printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z); - } else if (ipStart.ss_family == AF_INET6) { - v6db.push_back(_V6E()); - memcpy(v6db.back().start,reinterpret_cast(&ipStart)->sin6_addr.s6_addr,16); - memcpy(v6db.back().end,reinterpret_cast(&ipEnd)->sin6_addr.s6_addr,16); - v6db.back().lat = (float)lat; - v6db.back().lon = (float)lon; - v6db.back().x = x; - v6db.back().y = y; - v6db.back().z = z; - //printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z); - } - } - } -} - -long ClusterGeoIpService::_load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) -{ - // assumes _lock is locked - - FILE *f = fopen(pathToCsv,"rb"); - if (!f) - return -1; - - std::vector<_V4E> v4db; - std::vector<_V6E> v6db; - v4db.reserve(16777216); - v6db.reserve(16777216); - - char buf[4096]; - char linebuf[1024]; - unsigned int lineptr = 0; - for(;;) { - int n = (int)fread(buf,1,sizeof(buf),f); - if (n <= 0) - break; - for(int i=0;i 0)||(v6db.size() > 0)) { - std::sort(v4db.begin(),v4db.end()); - std::sort(v6db.begin(),v6db.end()); - - _pathToCsv = pathToCsv; - _ipStartColumn = ipStartColumn; - _ipEndColumn = ipEndColumn; - _latitudeColumn = latitudeColumn; - _longitudeColumn = longitudeColumn; - - _lastFileCheckTime = OSUtils::now(); - _csvModificationTime = OSUtils::getLastModified(pathToCsv); - _csvFileSize = OSUtils::getFileSize(pathToCsv); - - _v4db.swap(v4db); - _v6db.swap(v6db); - - return (long)(_v4db.size() + _v6db.size()); - } else { - return 0; - } -} - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER - -/* -int main(int argc,char **argv) -{ - char buf[1024]; - - ZeroTier::ClusterGeoIpService gip; - printf("loading...\n"); - gip.load("/Users/api/Code/ZeroTier/Infrastructure/root-servers/zerotier-one/cluster-geoip.csv",0,1,5,6); - printf("... done!\n"); fflush(stdout); - - while (gets(buf)) { // unsafe, testing only - ZeroTier::InetAddress addr(buf,0); - printf("looking up: %s\n",addr.toString().c_str()); fflush(stdout); - int x = 0,y = 0,z = 0; - if (gip.locate(addr,x,y,z)) { - //printf("%s: %d,%d,%d\n",addr.toString().c_str(),x,y,z); fflush(stdout); - } else { - printf("%s: not found!\n",addr.toString().c_str()); fflush(stdout); - } - } - - return 0; -} -*/ diff --git a/service/ClusterGeoIpService.hpp b/service/ClusterGeoIpService.hpp deleted file mode 100644 index 380f944f..00000000 --- a/service/ClusterGeoIpService.hpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 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 . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. - */ - -#ifndef ZT_CLUSTERGEOIPSERVICE_HPP -#define ZT_CLUSTERGEOIPSERVICE_HPP - -#ifdef ZT_ENABLE_CLUSTER - -#include -#include -#include -#include - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/Mutex.hpp" -#include "../node/NonCopyable.hpp" -#include "../node/InetAddress.hpp" - -namespace ZeroTier { - -/** - * Loads a GeoIP CSV into memory for fast lookup, reloading as needed - * - * This was designed around the CSV from https://db-ip.com but can be used - * with any similar GeoIP CSV database that is presented in the form of an - * IP range and lat/long coordinates. - * - * It loads the whole database into memory, which can be kind of large. If - * the CSV file changes, the changes are loaded automatically. - */ -class ClusterGeoIpService : NonCopyable -{ -public: - ClusterGeoIpService(); - ~ClusterGeoIpService(); - - /** - * Load or reload CSV file - * - * CSV column indexes start at zero. CSVs can be quoted with single or - * double quotes. Whitespace before or after commas is ignored. Backslash - * may be used for escaping whitespace as well. - * - * @param pathToCsv Path to (uncompressed) CSV file - * @param ipStartColumn Column with IP range start - * @param ipEndColumn Column with IP range end (inclusive) - * @param latitudeColumn Column with latitude - * @param longitudeColumn Column with longitude - * @return Number of valid records loaded or -1 on error (invalid file, not found, etc.) - */ - inline long load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn) - { - Mutex::Lock _l(_lock); - return _load(pathToCsv,ipStartColumn,ipEndColumn,latitudeColumn,longitudeColumn); - } - - /** - * Attempt to locate an IP - * - * This returns true if x, y, and z are set. If the return value is false - * the values of x, y, and z are undefined. - * - * @param ip IPv4 or IPv6 address - * @param x Reference to variable to receive X - * @param y Reference to variable to receive Y - * @param z Reference to variable to receive Z - * @return True if coordinates were set - */ - bool locate(const InetAddress &ip,int &x,int &y,int &z); - - /** - * @return True if IP database/service is available for queries (otherwise locate() will always be false) - */ - inline bool available() const - { - Mutex::Lock _l(_lock); - return ((_v4db.size() + _v6db.size()) > 0); - } - -private: - struct _V4E - { - uint32_t start; - uint32_t end; - float lat,lon; - int16_t x,y,z; - - inline bool operator<(const _V4E &e) const { return (start < e.start); } - }; - - struct _V6E - { - uint8_t start[16]; - uint8_t end[16]; - float lat,lon; - int16_t x,y,z; - - inline bool operator<(const _V6E &e) const { return (memcmp(start,e.start,16) < 0); } - }; - - static void _parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn); - long _load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn); - - std::string _pathToCsv; - int _ipStartColumn; - int _ipEndColumn; - int _latitudeColumn; - int _longitudeColumn; - - uint64_t _lastFileCheckTime; - uint64_t _csvModificationTime; - int64_t _csvFileSize; - - std::vector<_V4E> _v4db; - std::vector<_V6E> _v6db; - - Mutex _lock; -}; - -} // namespace ZeroTier - -#endif // ZT_ENABLE_CLUSTER - -#endif -- cgit v1.2.3 From dff8c02cfee9eaafae0974f3b070ff849a94c4ac Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 6 Jul 2017 12:33:00 -0700 Subject: Pull out and deprecate old cluster code. New cluster code will not be merged yet. --- node/IncomingPacket.cpp | 12 ++++++------ node/Peer.cpp | 18 ++++++++++++++++-- node/Peer.hpp | 17 ++++++++++++++++- service/OneService.cpp | 20 ++++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f0be96f9..ac8514c6 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1199,9 +1199,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { - //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - // peer->setClusterPreferred(a); - if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->redirect(tPtr,_path->localSocket(),a,now); + } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { @@ -1216,9 +1216,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { - //if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) - // peer->setClusterPreferred(a); - if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->redirect(tPtr,_path->localSocket(),a,now); + } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } else { diff --git a/node/Peer.cpp b/node/Peer.cpp index fb9a72b1..e16540b3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -170,11 +170,11 @@ void Peer::received( Mutex::Lock _l(_paths_m); _PeerPath *potentialNewPeerPath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { - if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) { + if ( ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) && ( (now - _v4Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { potentialNewPeerPath = &_v4Path; } } else if (path->address().ss_family == AF_INET6) { - if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) { + if ( ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) && ( (now - _v6Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { potentialNewPeerPath = &_v6Path; } } @@ -422,4 +422,18 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } +void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now) +{ + Mutex::Lock _l(_paths_m); + SharedPtr p(RR->topology->getPath(localSocket,remoteAddress)); + attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,p->nextOutgoingCounter()); + if (remoteAddress.ss_family == AF_INET) { + _v4Path.p = p; + _v4Path.sticky = now; + } else if (remoteAddress.ss_family == AF_INET6) { + _v6Path.p = p; + _v6Path.sticky = now; + } +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index ad2d0ddc..b24318ec 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -195,6 +195,20 @@ public: */ bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); + /** + * Specify remote path for this peer and forget others + * + * This overrides normal path learning and tells this peer to be found + * at this address, at least within the address's family. Other address + * families are not modified. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param localSocket Local socket as supplied by external code + * @param remoteAddress Remote address + * @param now Current time + */ + void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now); + /** * Reset paths within a given IP scope and address family * @@ -426,8 +440,9 @@ public: private: struct _PeerPath { - _PeerPath() : lr(0),p() {} + _PeerPath() : lr(0),sticky(0),p() {} uint64_t lr; // time of last valid ZeroTier packet + uint64_t sticky; // time last set as sticky SharedPtr p; }; diff --git a/service/OneService.cpp b/service/OneService.cpp index 6497ae20..6c2c9a8b 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -394,6 +394,8 @@ public: Phy _phy; Node *_node; SoftwareUpdater *_updater; + PhySocket *_localControlSocket4; + PhySocket *_localControlSocket6; bool _updateAutoApply; unsigned int _primaryPort; volatile unsigned int _udpPortPickerCounter; @@ -488,6 +490,8 @@ public: ,_phy(this,false,true) ,_node((Node *)0) ,_updater((SoftwareUpdater *)0) + ,_localControlSocket4((PhySocket *)0) + ,_localControlSocket6((PhySocket *)0) ,_updateAutoApply(false) ,_primaryPort(port) ,_udpPortPickerCounter(0) @@ -513,6 +517,8 @@ public: virtual ~OneServiceImpl() { _binder.closeAll(_phy); + _phy.close(_localControlSocket4); + _phy.close(_localControlSocket6); #ifdef ZT_USE_MINIUPNPC delete _portMapper; #endif @@ -652,6 +658,20 @@ public: return _termReason; } + // Bind local control socket + { + struct sockaddr_in lo4; + memset(&lo4,0,sizeof(lo4)); + lo4.sin_family = AF_INET; + lo4.sin_port = Utils::hton((uint16_t)_ports[0]); + _localControlSocket4 = _phy.tcpListen((const struct sockaddr *)&lo4); + struct sockaddr_in6 lo6; + memset(&lo6,0,sizeof(lo6)); + lo6.sin6_family = AF_INET6; + lo6.sin6_port = lo4.sin_port; + _localControlSocket6 = _phy.tcpListen((const struct sockaddr *)&lo6); + } + // Save primary port to a file so CLIs and GUIs can learn it easily char portstr[64]; Utils::ztsnprintf(portstr,sizeof(portstr),"%u",_ports[0]); -- cgit v1.2.3 From dab0fb9e05677bdc6294f196fcf8234892c582c1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 7 Jul 2017 16:58:05 -0700 Subject: Remote trace: plumbing, replace old TRACE with calls to Trace object. --- include/ZeroTierOne.h | 9 +- node/IncomingPacket.cpp | 180 ++++++++++------------------- node/Membership.cpp | 29 ++--- node/Multicaster.cpp | 4 - node/Network.cpp | 274 +++++++++----------------------------------- node/NetworkConfig.cpp | 2 + node/NetworkConfig.hpp | 7 ++ node/Node.cpp | 3 + node/Node.hpp | 7 -- node/OutboundMulticast.cpp | 13 --- node/Packet.cpp | 44 ------- node/Packet.hpp | 33 ++++-- node/Peer.cpp | 57 ++++----- node/RuntimeEnvironment.hpp | 3 +- node/SelfAwareness.cpp | 3 +- node/Switch.cpp | 71 +++--------- node/Topology.cpp | 10 +- node/Topology.hpp | 6 - node/Trace.cpp | 197 +++++++++++++++++++++++++++++++ node/Trace.hpp | 157 +++++++++++++++++++++++++ objects.mk | 1 + 21 files changed, 577 insertions(+), 533 deletions(-) create mode 100644 node/Trace.cpp create mode 100644 node/Trace.hpp (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 1365a9a0..f7681768 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -29,8 +29,8 @@ * engine. */ -#ifndef ZT_ZEROTIERONE_H -#define ZT_ZEROTIERONE_H +#ifndef ZT_ZEROTIER_API_H +#define ZT_ZEROTIER_API_H #include @@ -92,6 +92,11 @@ extern "C" { */ #define ZT_MAX_MTU 10000 +/** + * Maximum size of a remote trace message's serialized Dictionary + */ +#define ZT_MAX_REMOTE_TRACE_SIZE 10000 + /** * Maximum length of network short name */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ac8514c6..e1fb180c 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -48,6 +48,7 @@ #include "Capability.hpp" #include "Tag.hpp" #include "Revocation.hpp" +#include "Trace.hpp" namespace ZeroTier { @@ -63,11 +64,12 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // If this is marked as a packet via a trusted path, check source address and path ID. // Obviously if no trusted paths are configured this always returns false and such // packets are dropped on the floor. - if (RR->topology->shouldInboundPathBeTrusted(_path->address(),trustedPathId())) { + const uint64_t tpid = trustedPathId(); + if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { + RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,true); trusted = true; - TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId()); } else { - TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_path->address().toString().c_str(),trustedPathId(),_path->address().toString().c_str()); + RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,false); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -80,19 +82,18 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (!trusted) { if (!dearmor(peer->key())) { //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); - TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,packetId(),sourceAddress); return true; } } if (!uncompress()) { //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); - TRACE("dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)",sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); + RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"LZ4 decompression failed"); return true; } const Packet::Verb v = verb(); - //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_path->address().toString().c_str()); switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" @@ -121,9 +122,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) return false; } } catch ( ... ) { - // Exceptions are more informatively caught in _do...() handlers but - // this outer try/catch will catch anything else odd. - TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"unexpected exception in tryDecode() (outer)"); return true; } } @@ -135,8 +134,6 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); - /* Security note: we do not gate doERROR() with expectingReplyTo() to * avoid having to log every outgoing packet ID. Instead we put the * logic to determine whether we should consider an ERROR in each @@ -192,7 +189,6 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if ((network)&&(network->gate(tPtr,peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); } } break; @@ -202,7 +198,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ERROR,"unexpected exception"); } return true; } @@ -223,11 +219,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"protocol version too old"); return true; } if (fromAddress != id.address()) { - TRACE("dropped HELLO from %s(%s): identity does not match packet source address",fromAddress.toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"identity/address mismatch"); return true; } @@ -245,7 +241,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"address collision"); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); @@ -253,10 +249,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); } } else { - TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); } return true; @@ -264,7 +260,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); return true; } @@ -276,24 +272,26 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Sanity check: this basically can't happen if (alreadyAuthenticated) { - TRACE("dropped HELLO from %s(%s): somehow already authenticated with unknown peer?",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"illegal alreadyAuthenticated state"); return true; } // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) + if (!RR->node->rateGateIdentityVerification(now,_path->address())) { + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"rate limit exceeded"); return true; + } // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); return true; } // Check that identity's address is valid as per the derivation function if (!id.locallyValidate()) { - TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"invalid identity"); return true; } @@ -418,7 +416,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_HELLO,"unexpected exception"); } return true; } @@ -429,12 +427,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - if (!RR->node->expectingReplyTo(inRePacketId)) { - TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); + if (!RR->node->expectingReplyTo(inRePacketId)) return true; - } - - //TRACE("%s(%s): OK(%s)",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb)); switch(inReVerb) { @@ -447,11 +441,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); - - if (vProto < ZT_PROTO_VERSION_MIN) { - TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_path->address().toString().c_str()); + if (vProto < ZT_PROTO_VERSION_MIN) return true; - } InetAddress externalSurfaceAddress; unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; @@ -484,12 +475,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } else ptr += 2; } -#ifdef ZT_TRACE - const std::string tmp1(source().toString()); - const std::string tmp2(_path->address().toString()); - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u",tmp1.c_str(),tmp2.c_str(),vMajor,vMinor,vRevision,latency); -#endif - if (!hops()) peer->addDirectLatencyMeasurment((unsigned int)latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); @@ -516,7 +501,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const SharedPtr network(RR->node->network(nwid)); if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } @@ -527,8 +511,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags); - const SharedPtr network(RR->node->network(nwid)); if (network) { unsigned int offset = 0; @@ -555,7 +537,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { - TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_OK,"unexpected exception"); } return true; } @@ -563,10 +545,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { - TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + if ((!RR->topology->amRoot())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) return true; - } Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); @@ -595,7 +575,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_WHOIS,"unexpected exception"); } return true; } @@ -603,9 +583,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (!RR->topology->isUpstream(peer->identity())) { - TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str()); - } else { + if (RR->topology->isUpstream(peer->identity())) { const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); if (rendezvousWith) { @@ -614,22 +592,16 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { - RR->node->putPacket(tPtr,_path->localSocket(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + const uint64_t junk = RR->node->prng(); + RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); - TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - } else { - TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); } - } else { - TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str()); } - } else { - TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str()); } } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_RENDEZVOUS,"unexpected exception"); } return true; } @@ -652,16 +624,15 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } } else { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); + RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); } } else { - TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { - TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_FRAME,"unexpected exception"); } return true; } @@ -683,7 +654,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const } if (!network->gate(tPtr,peer)) { - TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; @@ -696,8 +667,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); - if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str()); + if ((!from)||(from == network->mac())) { peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -708,19 +678,19 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -743,12 +713,10 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { - TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { - TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_EXT_FRAME,"unexpected exception"); } return true; } @@ -756,10 +724,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (!peer->rateGateEchoRequest(RR->node->now())) { - TRACE("dropped ECHO from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + if (!peer->rateGateEchoRequest(RR->node->now())) return true; - } const uint64_t pid = packetId(); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); @@ -772,7 +738,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ECHO,"unexpected exception"); } return true; } @@ -820,7 +786,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { - TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); } return true; } @@ -828,10 +794,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { try { - if (!peer->rateGateCredentialsReceived(RR->node->now())) { - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); + if (!peer->rateGateCredentialsReceived(RR->node->now())) return true; - } CertificateOfMembership com; Capability cap; @@ -942,12 +906,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); - } catch (std::exception &exc) { - //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - //fprintf(stderr,"dropped NETWORK_CREDENTIALS from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); - TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); } return true; } @@ -975,12 +935,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void } peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); - } catch (std::exception &exc) { - //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): %s" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str(),exc.what()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what()); } catch ( ... ) { - //fprintf(stderr,"dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception" ZT_EOL_S,source().toString().c_str(),_path->address().toString().c_str()); - TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); } return true; } @@ -1003,7 +959,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); } return true; } @@ -1016,8 +972,6 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str()); - const SharedPtr network(RR->node->network(nwid)); if ((flags & 0x01) != 0) { @@ -1029,9 +983,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr network->addCredential(tPtr,com); else RR->mc->addCredential(tPtr,com,false); } - } catch ( ... ) { - TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str()); - } + } catch ( ... ) {} // discard invalid COMs } const bool trustEstablished = ((network)&&(network->gate(tPtr,peer))); @@ -1053,7 +1005,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { - TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); } return true; } @@ -1078,18 +1030,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } if (!network->gate(tPtr,peer)) { - TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } - if (network->config().multicastLimit == 0) { - TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); - return true; - } - unsigned int gatherLimit = 0; if ((flags & 0x02) != 0) { gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); @@ -1108,16 +1054,20 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); - //TRACE("<address().toString().c_str(),flags,frameLen); + if (network->config().multicastLimit == 0) { + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + return true; + } if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { if (!to.mac().isMulticast()) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } @@ -1126,16 +1076,15 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id()); + RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay return true; } } const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { + if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); - } } if (gatherLimit) { @@ -1158,7 +1107,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { - TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); } return true; } @@ -1170,7 +1119,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { - //TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); return true; } @@ -1202,10 +1150,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->redirect(tPtr,_path->localSocket(),a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); - } else { - //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; @@ -1219,10 +1164,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->redirect(tPtr,_path->localSocket(),a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); - } else { - //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); } } } break; @@ -1232,7 +1174,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); } return true; } @@ -1250,7 +1192,7 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con } peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false); } catch ( ... ) { - TRACE("dropped USER_MESSAGE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); + RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_USER_MESSAGE,"unexpected exception"); } return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index 466f9021..be6ea6a5 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -33,6 +33,7 @@ #include "Switch.hpp" #include "Packet.hpp" #include "Node.hpp" +#include "Trace.hpp" #define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3) @@ -128,27 +129,25 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme { const uint64_t newts = com.timestamp(); if (newts <= _comRevocationThreshold) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId()); + RR->t->credentialRejected(com,"revoked"); return ADD_REJECTED; } const uint64_t oldts = _com.timestamp(); if (newts < oldts) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId()); + RR->t->credentialRejected(com,"old"); return ADD_REJECTED; } - if ((newts == oldts)&&(_com == com)) { - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId()); + if ((newts == oldts)&&(_com == com)) return ADD_ACCEPTED_REDUNDANT; - } switch(com.verify(RR,tPtr)) { default: - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId()); + RR->t->credentialRejected(com,"invalid"); return ADD_REJECTED; case 0: - TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId()); _com = com; + RR->t->credentialAccepted(com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -162,27 +161,25 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot C *rc = remoteCreds.get(cred.id()); if (rc) { if (rc->timestamp() > cred.timestamp()) { - TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (older than credential we have)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialRejected(cred,"old"); return Membership::ADD_REJECTED; } - if (*rc == cred) { - //TRACE("addCredential(type==%d) for %s on %.16llx ACCEPTED (redundant)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + if (*rc == cred) return Membership::ADD_ACCEPTED_REDUNDANT; - } } const uint64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); if ((rt)&&(*rt >= cred.timestamp())) { - TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (timestamp below revocation threshold)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialRejected(cred,"revoked"); return Membership::ADD_REJECTED; } switch(cred.verify(RR,tPtr)) { default: - TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (invalid)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialRejected(cred,"invalid"); return Membership::ADD_REJECTED; case 0: - TRACE("addCredential(type==%d) for %s on %.16llx ACCEPTED (new)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId()); + RR->t->credentialAccepted(cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -201,12 +198,14 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme uint64_t *rt; switch(rev.verify(RR,tPtr)) { default: + RR->t->credentialRejected(rev,"invalid"); return ADD_REJECTED; case 0: { const Credential::Type ct = rev.type(); switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { + RR->t->credentialAccepted(rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } @@ -217,10 +216,12 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme rt = &(_revocations[credentialKey(ct,rev.credentialId())]); if (*rt < rev.threshold()) { *rt = rev.threshold(); + _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } return ADD_ACCEPTED_REDUNDANT; default: + RR->t->credentialRejected(rev,"invalid"); return ADD_REJECTED; } } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 52213364..fb7b068f 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -139,8 +139,6 @@ restart_member_scan: appendTo.setAt(totalAt,(uint32_t)totalKnown); appendTo.setAt(addedAt,(uint16_t)added); - //TRACE("..MC Multicaster::gather() attached %u of %u peers for %.16llx/%s (2)",n,(unsigned int)(gs->second.members.size() - skipped),nwid,mg.toString().c_str()); - return added; } @@ -386,8 +384,6 @@ void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGrou gs.members.push_back(MulticastGroupMember(member,now)); - //TRACE("..MC %s joined multicast group %.16llx/%s via %s",member.toString().c_str(),nwid,mg.toString().c_str(),((learnedFrom) ? learnedFrom.toString().c_str() : "(direct)")); - for(std::list::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) { if (tx->atLimit()) gs.txQueue.erase(tx++); diff --git a/node/Network.cpp b/node/Network.cpp index f2b6771b..575b0170 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -42,89 +42,12 @@ #include "NetworkController.hpp" #include "Node.hpp" #include "Peer.hpp" - -// Uncomment to make the rules engine dump trace info to stdout -//#define ZT_RULES_ENGINE_DEBUGGING 1 +#include "Trace.hpp" namespace ZeroTier { namespace { -#ifdef ZT_RULES_ENGINE_DEBUGGING -#define FILTER_TRACE(f,...) { snprintf(dpbuf,sizeof(dpbuf),f,##__VA_ARGS__); dlog.push_back(std::string(dpbuf)); } -static const char *_rtn(const ZT_VirtualNetworkRuleType rt) -{ - switch(rt) { - case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP"; - case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT"; - case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE"; - case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH"; - case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT"; - case ZT_NETWORK_RULE_ACTION_BREAK: return "ACTION_BREAK"; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS"; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: return "MATCH_DEST_ZEROTIER_ADDRESS"; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: return "MATCH_VLAN_ID"; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: return "MATCH_VLAN_PCP"; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: return "MATCH_VLAN_DEI"; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: return "MATCH_MAC_SOURCE"; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: return "MATCH_MAC_DEST"; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: return "MATCH_IPV4_SOURCE"; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: return "MATCH_IPV4_DEST"; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: return "MATCH_IPV6_SOURCE"; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: return "MATCH_IPV6_DEST"; - case ZT_NETWORK_RULE_MATCH_IP_TOS: return "MATCH_IP_TOS"; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: return "MATCH_IP_PROTOCOL"; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: return "MATCH_ETHERTYPE"; - case ZT_NETWORK_RULE_MATCH_ICMP: return "MATCH_ICMP"; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: return "MATCH_IP_SOURCE_PORT_RANGE"; - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: return "MATCH_IP_DEST_PORT_RANGE"; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: return "MATCH_CHARACTERISTICS"; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: return "MATCH_FRAME_SIZE_RANGE"; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: return "MATCH_TAGS_DIFFERENCE"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: return "MATCH_TAGS_BITWISE_AND"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: return "MATCH_TAGS_BITWISE_OR"; - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: return "MATCH_TAGS_BITWISE_XOR"; - default: return "???"; - } -} -static const void _dumpFilterTrace(const char *ruleName,uint8_t thisSetMatches,bool inbound,const Address &ztSource,const Address &ztDest,const MAC &macSource,const MAC &macDest,const std::vector &dlog,unsigned int frameLen,unsigned int etherType,const char *msg) -{ - static volatile unsigned long cnt = 0; - printf("%.6lu %c %s %s frameLen=%u etherType=%u" ZT_EOL_S, - cnt++, - ((thisSetMatches) ? 'Y' : '.'), - ruleName, - ((inbound) ? "INBOUND" : "OUTBOUND"), - frameLen, - etherType - ); - for(std::vector::const_iterator m(dlog.begin());m!=dlog.end();++m) - printf(" | %s" ZT_EOL_S,m->c_str()); - printf(" + %c %s->%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x->%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" ZT_EOL_S, - ((thisSetMatches) ? 'Y' : '.'), - ztSource.toString().c_str(), - ztDest.toString().c_str(), - (unsigned int)macSource[0], - (unsigned int)macSource[1], - (unsigned int)macSource[2], - (unsigned int)macSource[3], - (unsigned int)macSource[4], - (unsigned int)macSource[5], - (unsigned int)macDest[0], - (unsigned int)macDest[1], - (unsigned int)macDest[2], - (unsigned int)macDest[3], - (unsigned int)macDest[4], - (unsigned int)macDest[5] - ); - if (msg) - printf(" + (%s)" ZT_EOL_S,msg); - fflush(stdout); -} -#else -#define FILTER_TRACE(f,...) {} -#endif // ZT_RULES_ENGINE_DEBUGGING - // 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) { @@ -162,8 +85,10 @@ enum _doZtFilterResult DOZTFILTER_ACCEPT, DOZTFILTER_SUPER_ACCEPT }; + static _doZtFilterResult _doZtFilter( const RuntimeEnvironment *RR, + Trace::RuleResultLog &rrl, const NetworkConfig &nconf, const Membership *membership, // can be NULL const bool inbound, @@ -181,11 +106,6 @@ static _doZtFilterResult _doZtFilter( unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE bool &ccWatch) // MUTABLE -- set to true for WATCH target as opposed to normal TEE { -#ifdef ZT_RULES_ENGINE_DEBUGGING - char dpbuf[1024]; // used by FILTER_TRACE macro - std::vector dlog; -#endif // ZT_RULES_ENGINE_DEBUGGING - // Set to true if we are a TEE/REDIRECT/WATCH target bool superAccept = false; @@ -193,6 +113,8 @@ static _doZtFilterResult _doZtFilter( // ACTION with no MATCH entries preceding it is always taken. uint8_t thisSetMatches = 1; + rrl.clear(); + for(unsigned int rn=0;rnidentity.address()) { if (inbound) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"interpreted as super-ACCEPT on inbound since we are target"); -#endif // ZT_RULES_ENGINE_DEBUGGING return DOZTFILTER_SUPER_ACCEPT; } else { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"skipped as no-op on outbound since we are target"); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING } } else if (fwdAddr == ztDest) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,"skipped as no-op because destination is already target"); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING } else { if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_REDIRECT",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); -#endif // ZT_RULES_ENGINE_DEBUGGING ztDest = fwdAddr; return DOZTFILTER_REDIRECT; } else { -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING cc = fwdAddr; ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); @@ -259,18 +154,10 @@ static _doZtFilterResult _doZtFilter( } continue; case ZT_NETWORK_RULE_ACTION_BREAK: -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace("ACTION_BREAK",thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING return DOZTFILTER_NO_MATCH; // Unrecognized ACTIONs are ignored as no-ops default: -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING continue; } } else { @@ -290,10 +177,6 @@ static _doZtFilterResult _doZtFilter( } } -#ifdef ZT_RULES_ENGINE_DEBUGGING - _dumpFilterTrace(_rtn(rt),thisSetMatches,inbound,ztSource,ztDest,macSource,macDest,dlog,frameLen,etherType,(const char *)0); - dlog.clear(); -#endif // ZT_RULES_ENGINE_DEBUGGING thisSetMatches = 1; // reset to default true for next batch of entries continue; } @@ -301,8 +184,10 @@ static _doZtFilterResult _doZtFilter( // Circuit breaker: no need to evaluate an AND if the set's match state // is currently false since anything AND false is false. - if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) + if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) { + rrl.logSkipped(rn,thisSetMatches); continue; + } // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) uint8_t thisRuleMatches = 0; @@ -310,106 +195,82 @@ static _doZtFilterResult _doZtFilter( switch(rt) { case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); - FILTER_TRACE("%u %s %c %.10llx==%.10llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.zt,ztSource.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); - FILTER_TRACE("%u %s %c %.10llx==%.10llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.zt,ztDest.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_VLAN_ID: thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanId,(unsigned int)vlanId,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_VLAN_PCP: // NOT SUPPORTED YET thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanPcp,0,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_VLAN_DEI: // NOT SUPPORTED YET thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.vlanDei,0,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macSource); - FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macSource.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_MAC_DEST: thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macDest); - FILTER_TRACE("%u %s %c %.12llx=%.12llx -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),rules[rn].v.mac,macDest.toInt(),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).toString().c_str(),InetAddress((const void *)(frameData + 12),4,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv4] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IPV4_DEST: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).toString().c_str(),InetAddress((const void *)(frameData + 16),4,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv4] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).toString().c_str(),InetAddress((const void *)(frameData + 8),16,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IPV6_DEST: if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0))); - FILTER_TRACE("%u %s %c %s contains %s -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).toString().c_str(),InetAddress((const void *)(frameData + 24),16,0).toIpString().c_str(),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IP_TOS: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - //thisRuleMatches = (uint8_t)(rules[rn].v.ipTos == ((frameData[1] & 0xfc) >> 2)); const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - FILTER_TRACE("%u %s %c (IPv4) %u&%u==%u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)tosMasked,(unsigned int)rules[rn].v.ipTos.mask,(unsigned int)rules[rn].v.ipTos.value[0],(unsigned int)rules[rn].v.ipTos.value[1],(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); - FILTER_TRACE("%u %s %c (IPv4) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipProtocol,(unsigned int)frameData[9],(unsigned int)thisRuleMatches); } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); - FILTER_TRACE("%u %s %c (IPv6) %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.ipProtocol,proto,(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_ETHERTYPE: thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); - FILTER_TRACE("%u %s %c %u==%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.etherType,etherType,(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_ICMP: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { @@ -425,14 +286,11 @@ static _doZtFilterResult _doZtFilter( } else { thisRuleMatches = 0; } - FILTER_TRACE("%u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[ihl],(int)rules[rn].v.icmp.type,(int)frameData[ihl+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [IPv4 frame invalid] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not ICMP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; @@ -447,21 +305,16 @@ static _doZtFilterResult _doZtFilter( } else { thisRuleMatches = 0; } - FILTER_TRACE("%u %s %c (IPv6) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[pos],(int)rules[rn].v.icmp.type,(int)frameData[pos+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not ICMPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; - break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { @@ -482,7 +335,6 @@ static _doZtFilterResult _doZtFilter( } thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - FILTER_TRACE("%u %s %c (IPv4) %d in %d-%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),p,(int)rules[rn].v.port[0],(int)rules[rn].v.port[1],(unsigned int)thisRuleMatches); } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { @@ -501,14 +353,11 @@ static _doZtFilterResult _doZtFilter( break; } thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - FILTER_TRACE("%u %s %c (IPv6) %d in %d-%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),p,(int)rules[rn].v.port[0],(int)rules[rn].v.port[1],(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { @@ -570,15 +419,12 @@ static _doZtFilterResult _doZtFilter( } } thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); - FILTER_TRACE("%u %s %c (%.16llx | %.16llx)!=0 -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),cf,rules[rn].v.characteristics,(unsigned int)thisRuleMatches); } break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); - FILTER_TRACE("%u %s %c %u in %u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),frameLen,(unsigned int)rules[rn].v.frameSize[0],(unsigned int)rules[rn].v.frameSize[1],(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_RANDOM: thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability); - FILTER_TRACE("%u %s %c -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)thisRuleMatches); break; case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: @@ -594,26 +440,20 @@ static _doZtFilterResult _doZtFilter( if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x | remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%.8x ^ remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value)); - FILTER_TRACE("%u %s %c TAG %u local:%.8x and remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,ltv,rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { // sanity check, can't really happen thisRuleMatches = 0; } } else { if ((inbound)&&(!superAccept)) { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } else { // Outbound side is not strict since if we have to match both tags and // we are sending a first packet to a recipient, we probably do not know @@ -621,43 +461,35 @@ static _doZtFilterResult _doZtFilter( // once we get their tag. If we are a tee/redirect target we are also // not strict since we likely do not have these tags. thisRuleMatches = 1; - FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side and TEE/REDIRECT targets are not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } break; case ZT_NETWORK_RULE_MATCH_TAG_SENDER: case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { if (superAccept) { thisRuleMatches = 1; - FILTER_TRACE("%u %s %c we are a TEE/REDIRECT target -> 1",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) { const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); if (remoteTag) { thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,remoteTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { // If we are checking the receiver and this is an outbound packet, we // can't be strict since we may not yet know the receiver's tag. thisRuleMatches = 1; - FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 1 (outbound receiver match is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } } else { // sender and outbound or receiver and inbound const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,localTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); } else { thisRuleMatches = 0; - FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); } } } break; @@ -669,6 +501,8 @@ static _doZtFilterResult _doZtFilter( break; } + rrl.log(rn,thisRuleMatches,thisSetMatches); + if ((rules[rn].t & 0x40)) thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); @@ -761,33 +595,34 @@ bool Network::filterOutgoingPacket( const uint64_t now = RR->node->now(); Address ztFinalDest(ztDest); int localCapabilityIndex = -1; - bool accept = false; + int accept = 0; + Trace::RuleResultLog rrl,crrl; + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; Mutex::Lock _l(_lock); Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0; - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - switch(_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { + switch(_doZtFilter(RR,rrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { - case DOZTFILTER_NO_MATCH: + case DOZTFILTER_NO_MATCH: { for(unsigned int c=0;c<_config.capabilityCount;++c) { ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match Address cc2; unsigned int ccLength2 = 0; bool ccWatch2 = false; - switch (_doZtFilter(RR,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) { + switch (_doZtFilter(RR,crrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side + case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side in capabilities localCapabilityIndex = (int)c; - accept = true; + accept = 1; if ((!noTee)&&(cc2)) { Membership &m2 = _membership(cc2); @@ -809,15 +644,20 @@ bool Network::filterOutgoingPacket( if (accept) break; } - break; + } break; case DOZTFILTER_DROP: + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side - accept = true; + accept = 1; + break; + + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; break; } @@ -854,11 +694,17 @@ bool Network::filterOutgoingPacket( outp.compress(); RR->sw->send(tPtr,outp,true); + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; // DROP locally, since we redirected } else { + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); return true; } } else { + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; } } @@ -875,26 +721,27 @@ int Network::filterIncomingPacket( const unsigned int vlanId) { Address ztFinalDest(ztDest); + Trace::RuleResultLog rrl,crrl; int accept = 0; + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; + const Capability *c = (Capability *)0; Mutex::Lock _l(_lock); Membership &membership = _membership(sourcePeer->address()); - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - switch (_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { + switch (_doZtFilter(RR,rrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch)) { case DOZTFILTER_NO_MATCH: { Membership::CapabilityIterator mci(membership,_config); - const Capability *c; while ((c = mci.next())) { ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match Address cc2; unsigned int ccLength2 = 0; bool ccWatch2 = false; - switch(_doZtFilter(RR,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) { + switch(_doZtFilter(RR,crrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2)) { case DOZTFILTER_NO_MATCH: case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern break; @@ -927,6 +774,8 @@ int Network::filterIncomingPacket( } break; case DOZTFILTER_DROP: + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -966,10 +815,14 @@ int Network::filterIncomingPacket( outp.compress(); RR->sw->send(tPtr,outp,true); + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP locally, since we redirected } } + if (_config.remoteTraceTarget) + RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); return accept; } @@ -1025,15 +878,10 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add totalLength = chunk.at(ptr); ptr += 4; chunkIndex = chunk.at(ptr); ptr += 4; - if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end - TRACE("discarded chunk from %s: invalid length or length overflow",source.toString().c_str()); + if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) // >= since we need room for a null at the end return 0; - } - - if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: unrecognized signature type",source.toString().c_str()); + if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) return 0; - } const uint8_t *sig = reinterpret_cast(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN)); // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use @@ -1058,14 +906,10 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add // If it's not a duplicate, check chunk signature const Identity controllerId(RR->topology->getIdentity(tPtr,controller())); - if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? - TRACE("unable to verify chunk from %s: don't have controller identity",source.toString().c_str()); + if (!controllerId) // we should always have the controller identity by now, otherwise how would we have queried it the first time? return 0; - } - if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) { - TRACE("discarded chunk from %s: signature check failed",source.toString().c_str()); + if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) return 0; - } // New properly verified chunks can be flooded "virally" through the network if (fastPropagate) { @@ -1095,7 +939,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add c = &(_incomingConfigChunks[i]); } } else { - TRACE("discarded single-chunk unsigned legacy config: this is only allowed if the sender is the controller itself"); + // Single-chunk unsigned legacy configs are only allowed from the controller itself return 0; } @@ -1188,9 +1032,7 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD } return 2; // OK and configuration has changed - } catch ( ... ) { - TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id); - } + } catch ( ... ) {} // ignore invalid configs return 0; } @@ -1293,6 +1135,8 @@ void Network::requestConfiguration(void *tPtr) rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); + RR->t->networkConfigRequestSent(*this,ctrl); + if (ctrl == RR->identity.address()) { if (RR->localNetworkController) { RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd); @@ -1302,8 +1146,6 @@ void Network::requestConfiguration(void *tPtr) return; } - TRACE("requesting netconf for network %.16llx from controller %s",(unsigned long long)_id,ctrl.toString().c_str()); - Packet outp(ctrl,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append((uint64_t)_id); const unsigned int rmdSize = rmd.sizeBytes(); @@ -1337,9 +1179,7 @@ bool Network::gate(void *tPtr,const SharedPtr &peer) return true; } } - } catch ( ... ) { - TRACE("gate() check failed for peer %s: unexpected exception",peer->address().toString().c_str()); - } + } catch ( ... ) {} return false; } diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index e5929923..0bf4bc19 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -47,6 +47,7 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; @@ -217,6 +218,7 @@ bool NetworkConfig::fromDictionary(const DictionaryremoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET); this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index fdd078d5..8b3b3619 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -159,6 +159,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_REVISION "r" // address of member #define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id" +// remote trace target +#define ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET "tt" // flags(hex) #define ZT_NETWORKCONFIG_DICT_KEY_FLAGS "f" // integer(hex) @@ -462,6 +464,11 @@ public: */ Address issuedTo; + /** + * If non-NULL, remote traces related to this network are sent here + */ + Address remoteTraceTarget; + /** * Flags (64-bit) */ diff --git a/node/Node.cpp b/node/Node.cpp index e28accee..c54ca450 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,6 +46,7 @@ #include "Identity.hpp" #include "SelfAwareness.hpp" #include "Network.hpp" +#include "Trace.hpp" namespace ZeroTier { @@ -108,6 +109,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } try { + RR->t = new Trace(RR); RR->sw = new Switch(RR); RR->mc = new Multicaster(RR); RR->topology = new Topology(RR,tptr); @@ -133,6 +135,7 @@ Node::~Node() delete RR->topology; delete RR->mc; delete RR->sw; + delete RR->t; } ZT_ResultCode Node::processWirePacket( diff --git a/node/Node.hpp b/node/Node.hpp index 40903f7c..57b99fe9 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -48,13 +48,6 @@ #include "NetworkController.hpp" #include "Hashtable.hpp" -#undef TRACE -#ifdef ZT_TRACE -#define TRACE(f,...) RR->node->postTrace(__FILE__,__LINE__,f,##__VA_ARGS__) -#else -#define TRACE(f,...) {} -#endif - // Bit mask for "expecting reply" hash #define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 #define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index a2341ffd..04ba2c2a 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -65,18 +65,6 @@ void OutboundMulticast::init( if (gatherLimit) flags |= 0x02; - /* - TRACE(">>MC %.16llx INIT %.16llx/%s limit %u gatherLimit %u from %s to %s length %u", - (unsigned long long)this, - nwid, - dest.toString().c_str(), - limit, - gatherLimit, - (src) ? src.toString().c_str() : MAC(RR->identity.address(),nwid).toString().c_str(), - dest.toString().c_str(), - len); - */ - _packet.setSource(RR->identity.address()); _packet.setVerb(Packet::VERB_MULTICAST_FRAME); _packet.append((uint64_t)nwid); @@ -98,7 +86,6 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const A const SharedPtr nw(RR->node->network(_nwid)); const Address toAddr2(toAddr); if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0))) { - //TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str()); _packet.newInitializationVector(); _packet.setDestination(toAddr2); RR->node->expectReplyTo(_packet.packetId()); diff --git a/node/Packet.cpp b/node/Packet.cpp index 6e1b36ac..d3f7dfd6 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1061,50 +1061,6 @@ static inline int LZ4_decompress_safe(const char* source, char* dest, int compre const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -#ifdef ZT_TRACE - -const char *Packet::verbString(Verb v) -{ - switch(v) { - case VERB_NOP: return "NOP"; - case VERB_HELLO: return "HELLO"; - case VERB_ERROR: return "ERROR"; - case VERB_OK: return "OK"; - case VERB_WHOIS: return "WHOIS"; - case VERB_RENDEZVOUS: return "RENDEZVOUS"; - case VERB_FRAME: return "FRAME"; - case VERB_EXT_FRAME: return "EXT_FRAME"; - case VERB_ECHO: return "ECHO"; - case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; - case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; - case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; - case VERB_NETWORK_CONFIG: return "NETWORK_CONFIG"; - case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; - case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; - case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; - case VERB_USER_MESSAGE: return "USER_MESSAGE"; - } - return "(unknown)"; -} - -const char *Packet::errorString(ErrorCode e) -{ - switch(e) { - case ERROR_NONE: return "NONE"; - case ERROR_INVALID_REQUEST: return "INVALID_REQUEST"; - case ERROR_BAD_PROTOCOL_VERSION: return "BAD_PROTOCOL_VERSION"; - case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; - case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; - case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; - case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; - case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; - case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; - } - return "(unknown)"; -} - -#endif // ZT_TRACE - void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) { uint8_t mangledKey[32]; diff --git a/node/Packet.hpp b/node/Packet.hpp index a76d4180..4941e96a 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -42,12 +42,6 @@ #include "Utils.hpp" #include "Buffer.hpp" -//#ifdef ZT_USE_SYSTEM_LZ4 -//#include -//#else -//#include "../ext/lz4/lz4.h" -//#endif - /** * Protocol version -- incremented only for major changes * @@ -969,7 +963,27 @@ public: * ZeroTier, Inc. itself. We recommend making up random ones for your own * implementations. */ - VERB_USER_MESSAGE = 0x14 + VERB_USER_MESSAGE = 0x14, + + /** + * A trace for remote debugging or diagnostics: + * <[8] 64-bit instance ID> + * <[2] 16-bit length of Dictionary> + * <[...] dictionary containing trace information> + * + * This message contains a remote trace event. Remote trace events can + * be sent to observers configured at the network level for those that + * pertain directly to actiity on a network, or to global observers if + * locally configured. + * + * The instance ID is a random 64-bit value generated by each ZeroTier + * node on startup. This is helpful in identifying traces from different + * members of a cluster. + * + * The Dictionary serialization format is the same as used for network + * configurations. The maximum size of a trace is 10000 bytes. + */ + VERB_REMOTE_TRACE = 0x15 }; /** @@ -1005,11 +1019,6 @@ public: ERROR_UNWANTED_MULTICAST = 0x08 }; -#ifdef ZT_TRACE - static const char *verbString(Verb v); - static const char *errorString(ErrorCode e); -#endif - template Packet(const Buffer &b) : Buffer(b) diff --git a/node/Peer.cpp b/node/Peer.cpp index e16540b3..79a4bc90 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -33,6 +33,7 @@ #include "Network.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" +#include "Trace.hpp" namespace ZeroTier { @@ -168,22 +169,25 @@ void Peer::received( if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) { Mutex::Lock _l(_paths_m); - _PeerPath *potentialNewPeerPath = (_PeerPath *)0; + + _PeerPath *replacablePath = (_PeerPath *)0; if (path->address().ss_family == AF_INET) { if ( ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) && ( (now - _v4Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - potentialNewPeerPath = &_v4Path; + replacablePath = &_v4Path; } } else if (path->address().ss_family == AF_INET6) { if ( ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) && ( (now - _v6Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - potentialNewPeerPath = &_v6Path; + replacablePath = &_v6Path; } } - if (potentialNewPeerPath) { + + if (replacablePath) { if (verb == Packet::VERB_OK) { - potentialNewPeerPath->lr = now; - potentialNewPeerPath->p = path; + RR->t->peerLearnedNewPath(*this,replacablePath->p,path,packetId); + replacablePath->lr = now; + replacablePath->p = path; } else { - TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); + RR->t->peerConfirmingUnknownPath(*this,path,packetId,verb); attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } @@ -211,16 +215,6 @@ void Peer::received( } if (pathsToPush.size() > 0) { -#ifdef ZT_TRACE - std::string ps; - for(std::vector::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) { - if (ps.length() > 0) - ps.push_back(','); - ps.append(p->toString()); - } - TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str()); -#endif - std::vector::const_iterator p(pathsToPush.begin()); while (p != pathsToPush.end()) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); @@ -424,16 +418,27 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now) { - Mutex::Lock _l(_paths_m); - SharedPtr p(RR->topology->getPath(localSocket,remoteAddress)); - attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,p->nextOutgoingCounter()); - if (remoteAddress.ss_family == AF_INET) { - _v4Path.p = p; - _v4Path.sticky = now; - } else if (remoteAddress.ss_family == AF_INET6) { - _v6Path.p = p; - _v6Path.sticky = now; + if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check + return; + + SharedPtr op; + SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); + + { + Mutex::Lock _l(_paths_m); + if (remoteAddress.ss_family == AF_INET) { + op = _v4Path.p; + _v4Path.p = np; + _v4Path.sticky = now; + } else if (remoteAddress.ss_family == AF_INET6) { + op = _v6Path.p; + _v6Path.p = np; + _v6Path.sticky = now; + } } + + RR->t->peerRedirected(*this,op,np); } } // namespace ZeroTier diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 94b96d34..0bb78599 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -42,7 +42,7 @@ class Node; class Multicaster; class NetworkController; class SelfAwareness; -class Cluster; +class Trace; /** * Holds global state for an instance of ZeroTier::Node @@ -93,6 +93,7 @@ public: * These are constant and never null after startup unless indicated. */ + Trace *t; Switch *sw; Multicaster *mc; Topology *topology; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 3e3397f5..173230fb 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -39,6 +39,7 @@ #include "Packet.hpp" #include "Peer.hpp" #include "Switch.hpp" +#include "Trace.hpp" // Entry timeout -- make it fairly long since this is just to prevent stale buildup #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 @@ -81,7 +82,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope - TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str()); + RR->t->resettingPathsInScope(reporter,reporterPhysicalAddress,myPhysicalAddress,scope); entry.mySurface = myPhysicalAddress; entry.ts = now; diff --git a/node/Switch.cpp b/node/Switch.cpp index a77ca89e..2fbd243b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -43,26 +43,10 @@ #include "Peer.hpp" #include "SelfAwareness.hpp" #include "Packet.hpp" +#include "Trace.hpp" namespace ZeroTier { -#ifdef ZT_TRACE -static const char *etherTypeName(const unsigned int etherType) -{ - switch(etherType) { - case ZT_ETHERTYPE_IPV4: return "IPV4"; - case ZT_ETHERTYPE_ARP: return "ARP"; - case ZT_ETHERTYPE_RARP: return "RARP"; - case ZT_ETHERTYPE_ATALK: return "ATALK"; - case ZT_ETHERTYPE_AARP: return "AARP"; - case ZT_ETHERTYPE_IPX_A: return "IPX_A"; - case ZT_ETHERTYPE_IPX_B: return "IPX_B"; - case ZT_ETHERTYPE_IPV6: return "IPV6"; - } - return "UNKNOWN"; -} -#endif // ZT_TRACE - Switch::Switch(const RuntimeEnvironment *renv) : RR(renv), _lastBeaconResponse(0), @@ -123,8 +107,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if (relayTo) relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); } - } else { - TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str()); } } else { // Fragment looks like ours @@ -143,7 +125,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((!rq->timestamp)||(rq->packetId != fragmentPacketId)) { // No packet found, so we received a fragment without its head. - //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str()); rq->timestamp = now; rq->packetId = fragmentPacketId; @@ -153,14 +134,12 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre rq->complete = false; } else if (!(rq->haveFragments & (1 << fragmentNumber))) { // We have other fragments and maybe the head, so add this one and check - //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str()); rq->frags[fragmentNumber - 1] = fragment; rq->totalFragments = totalFragments; if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) { // We have all fragments -- assemble and process full Packet - //TRACE("packet %.16llx is complete, assembling and processing...",fragmentPacketId); for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); @@ -182,8 +161,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre const Address destination(reinterpret_cast(data) + 8,ZT_ADDRESS_LENGTH); const Address source(reinterpret_cast(data) + 13,ZT_ADDRESS_LENGTH); - //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size()); - if (source == RR->identity.address()) return; @@ -258,8 +235,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if (relayTo) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } - } else { - TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str()); } } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { // Packet is the head of a fragmented packet series @@ -280,7 +255,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((!rq->timestamp)||(rq->packetId != packetId)) { // If we have no other fragments yet, create an entry and save the head - //TRACE("fragment (0/?) of %.16llx from %s",pid,fromAddr.toString().c_str()); rq->timestamp = now; rq->packetId = packetId; @@ -293,7 +267,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) { // We have all fragments -- assemble and process full Packet - //TRACE("packet %.16llx is complete, assembling and processing...",pid); rq->frag0.init(data,len,path,now); for(unsigned int f=1;ftotalFragments;++f) @@ -333,11 +306,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre // -------------------------------------------------------------------- } } - } catch (std::exception &ex) { - TRACE("dropped packet from %s: unexpected exception: %s",fromAddr.toString().c_str(),ex.what()); - } catch ( ... ) { - TRACE("dropped packet from %s: unexpected exception: (unknown)",fromAddr.toString().c_str()); - } + } catch ( ... ) {} // sanity check, should be caught elsewhere } void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) @@ -349,7 +318,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const bool fromBridged; if ((fromBridged = (from != network->mac()))) { if (!network->config().permitsBridging(RR->identity.address())) { - TRACE("%.16llx: %s -> %s %s not forwarded, bridging disabled or this peer not a bridge",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"not a bridge"); return; } } @@ -371,7 +340,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them - TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"broadcast disabled"); return; } } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { @@ -424,7 +393,6 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const if ((v6EmbeddedAddress)&&(v6EmbeddedAddress != RR->identity.address())) { const MAC peerMac(v6EmbeddedAddress,network->id()); - TRACE("IPv6 NDP emulation: %.16llx: forging response for %s/%s",network->id(),v6EmbeddedAddress.toString().c_str(),peerMac.toString().c_str()); uint8_t adv[72]; adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00; @@ -460,7 +428,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // Check this after NDP emulation, since that has to be allowed in exactly this case if (network->config().multicastLimit == 0) { - TRACE("%.16llx: dropped multicast: not allowed on network",network->id()); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"multicast disabled"); return; } @@ -471,11 +439,9 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const if (fromBridged) network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now()); - //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),multicastGroup.toString().c_str(),etherTypeName(etherType),len); - // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -501,7 +467,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -526,7 +492,6 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const send(tPtr,outp,true); } - //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); } else { // Destination is bridged behind a remote peer @@ -534,7 +499,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // for each ZT destination are also done below. This is the same rationale // and design as for multicast. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -583,7 +548,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const outp.compress(); send(tPtr,outp,true); } else { - TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); } } } @@ -591,11 +556,8 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const void Switch::send(void *tPtr,Packet &packet,bool encrypt) { - if (packet.destination() == RR->identity.address()) { - TRACE("BUG: caught attempt to send() to self, ignored"); + if (packet.destination() == RR->identity.address()) return; - } - if (!_trySend(tPtr,packet,encrypt)) { Mutex::Lock _l(_txQueue_m); _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); @@ -604,13 +566,8 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) void Switch::requestWhois(void *tPtr,const Address &addr) { -#ifdef ZT_TRACE - if (addr == RR->identity.address()) { - fprintf(stderr,"FATAL BUG: Switch::requestWhois() caught attempt to WHOIS self" ZT_EOL_S); - abort(); - } -#endif - + if (addr == RR->identity.address()) + return; bool inserted = false; { Mutex::Lock _l(_outstandingWhoisRequests_m); @@ -670,12 +627,10 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) const unsigned long since = (unsigned long)(now - r->lastSent); if (since >= ZT_WHOIS_RETRY_DELAY) { if (r->retries >= ZT_MAX_WHOIS_RETRIES) { - TRACE("WHOIS %s timed out",a->toString().c_str()); _outstandingWhoisRequests.erase(*a); } else { r->lastSent = now; r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); - TRACE("WHOIS %s (retry %u)",a->toString().c_str(),r->retries); ++r->retries; nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); } @@ -691,7 +646,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str()); + RR->t->txTimedOut(txi->dest); _txQueue.erase(txi++); } else ++txi; } diff --git a/node/Topology.cpp b/node/Topology.cpp index e7bbdfae..edca0180 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -90,11 +90,6 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { -#ifdef ZT_TRACE - if ((!peer)||(peer->address() == RR->identity.address())) - return SharedPtr(); -#endif - SharedPtr np; { Mutex::Lock _l(_peers_m); @@ -103,16 +98,13 @@ SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) hp = peer; np = hp; } - return np; } SharedPtr Topology::getPeer(void *tPtr,const Address &zta) { - if (zta == RR->identity.address()) { - TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); + if (zta == RR->identity.address()) return SharedPtr(); - } { Mutex::Lock _l(_peers_m); diff --git a/node/Topology.hpp b/node/Topology.hpp index 5f3e2da1..30e58abc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -330,12 +330,6 @@ public: Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { -#ifdef ZT_TRACE - if (!(*p)) { - fprintf(stderr,"FATAL BUG: eachPeer() caught NULL peer for %s -- peer pointers in Topology should NEVER be NULL" ZT_EOL_S,a->toString().c_str()); - abort(); - } -#endif f(*this,*((const SharedPtr *)p)); } } diff --git a/node/Trace.cpp b/node/Trace.cpp new file mode 100644 index 00000000..6b68cfe7 --- /dev/null +++ b/node/Trace.cpp @@ -0,0 +1,197 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "Trace.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Node.hpp" +#include "Utils.hpp" + +namespace ZeroTier { + +#ifdef ZT_TRACE +static const char *packetVerbString(Packet::Verb v) +{ + switch(v) { + case Packet::VERB_NOP: return "NOP"; + case Packet::VERB_HELLO: return "HELLO"; + case Packet::Packet::VERB_ERROR: return "ERROR"; + case Packet::VERB_OK: return "OK"; + case Packet::VERB_WHOIS: return "WHOIS"; + case Packet::VERB_RENDEZVOUS: return "RENDEZVOUS"; + case Packet::VERB_FRAME: return "FRAME"; + case Packet::VERB_EXT_FRAME: return "EXT_FRAME"; + case Packet::VERB_ECHO: return "ECHO"; + case Packet::VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; + case Packet::VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; + case Packet::VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; + case Packet::VERB_NETWORK_CONFIG: return "NETWORK_CONFIG"; + case Packet::VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; + case Packet::VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; + case Packet::VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; + case Packet::VERB_USER_MESSAGE: return "USER_MESSAGE"; + case Packet::VERB_REMOTE_TRACE: return "REMOTE_TRACE"; + } + return "(unknown)"; +} + +static const char *packetErrorString(Packet::ErrorCode e) +{ + switch(e) { + case Packet::ERROR_NONE: return "NONE"; + case Packet::ERROR_INVALID_REQUEST: return "INVALID_REQUEST"; + case Packet::ERROR_BAD_PROTOCOL_VERSION: return "BAD_PROTOCOL_VERSION"; + case Packet::ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND"; + case Packet::ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION"; + case Packet::ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION"; + case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE"; + case Packet::ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED"; + case Packet::ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST"; + } + return "(unknown)"; +} +#endif + +void Trace::resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) +{ +} + +void Trace::txTimedOut(const Address &destination) +{ +} + +void Trace::peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) +{ +} + +void Trace::peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) +{ +} + +void Trace::peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) +{ +} + +void Trace::outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) +{ +} + +void Trace::incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) +{ +} + +void Trace::incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source) +{ +} + +void Trace::incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason) +{ +} + +void Trace::incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) +{ +} + +void Trace::networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) +{ +} + +void Trace::networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) +{ +} + +void Trace::networkConfigRequestSent(const Network &network,const Address &controller) +{ +} + +void Trace::networkFilter( + const Network &network, + const RuleResultLog &primaryRuleSetLog, + const RuleResultLog *const matchingCapabilityRuleSetLog, + const Capability *const matchingCapability, + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const bool noTee, + const bool inbound, + const int accept) +{ +} + +void Trace::credentialRejected(const CertificateOfMembership &c,const char *reason) +{ +} + +void Trace::credentialRejected(const CertificateOfOwnership &c,const char *reason) +{ +} + +void Trace::credentialRejected(const CertificateOfRepresentation &c,const char *reason) +{ +} + +void Trace::credentialRejected(const Capability &c,const char *reason) +{ +} + +void Trace::credentialRejected(const Tag &c,const char *reason) +{ +} + +void Trace::credentialRejected(const Revocation &c,const char *reason) +{ +} + +void Trace::credentialAccepted(const CertificateOfMembership &c) +{ +} + +void Trace::credentialAccepted(const CertificateOfOwnership &c) +{ +} + +void Trace::credentialAccepted(const CertificateOfRepresentation &c) +{ +} + +void Trace::credentialAccepted(const Capability &c) +{ +} + +void Trace::credentialAccepted(const Tag &c) +{ +} + +void Trace::credentialAccepted(const Revocation &c) +{ +} + +} // namespace ZeroTier diff --git a/node/Trace.hpp b/node/Trace.hpp new file mode 100644 index 00000000..65d1acf1 --- /dev/null +++ b/node/Trace.hpp @@ -0,0 +1,157 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2017 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 . + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_TRACE_HPP +#define ZT_TRACE_HPP + +#include +#include +#include +#include + +#include "../include/ZeroTierOne.h" + +#include "Constants.hpp" +#include "SharedPtr.hpp" +#include "Packet.hpp" +#include "Credential.hpp" +#include "InetAddress.hpp" + +namespace ZeroTier { + +class RuntimeEnvironment; +class Address; +class Identity; +class Peer; +class Path; +class Network; +class NetworkConfig; +class MAC; +class CertificateOfMembership; +class CertificateOfOwnership; +class CertificateOfRepresentation; +class Revocation; +class Tag; +class Capability; + +/** + * Remote tracing and trace logging handler + */ +class Trace +{ +public: + /** + * Filter rule evaluation result log + * + * Each rule in a rule set gets a four-bit log entry. A log entry + * of zero means not evaluated. Otherwise each four-bit log entry + * contains two two-bit values of 01 for 'false' and 10 for 'true'. + * As with four-bit rules an 00 value here means this was not + * evaluated or was not relevant. + */ + class RuleResultLog + { + public: + RuleResultLog() {} + + inline void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches) + { + _l[rn >> 1] |= ( ((thisRuleMatches + 1) << 2) | (thisSetMatches + 1) ) << ((rn & 1) << 2); + } + inline void logSkipped(const unsigned int rn,const uint8_t thisSetMatches) + { + _l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2); + } + + inline void clear() + { + memset(_l,0,sizeof(_l)); + } + + inline const uint8_t *data() const { return _l; } + inline unsigned int sizeBytes() const { return (unsigned int)sizeof(_l); } + + private: + uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; + }; + + Trace(const RuntimeEnvironment *renv) : RR(renv) {} + + void resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); + void txTimedOut(const Address &destination); + + void peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); + void peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); + void peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); + + void outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); + + void incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); + void incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source); + void incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason); + void incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); + + void networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); + void networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); + + void networkConfigRequestSent(const Network &network,const Address &controller); + void networkFilter( + const Network &network, + const RuleResultLog &primaryRuleSetLog, + const RuleResultLog *const matchingCapabilityRuleSetLog, + const Capability *const matchingCapability, + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const bool noTee, + const bool inbound, + const int accept); + + void credentialRejected(const CertificateOfMembership &c,const char *reason); + void credentialRejected(const CertificateOfOwnership &c,const char *reason); + void credentialRejected(const CertificateOfRepresentation &c,const char *reason); + void credentialRejected(const Capability &c,const char *reason); + void credentialRejected(const Tag &c,const char *reason); + void credentialRejected(const Revocation &c,const char *reason); + void credentialAccepted(const CertificateOfMembership &c); + void credentialAccepted(const CertificateOfOwnership &c); + void credentialAccepted(const CertificateOfRepresentation &c); + void credentialAccepted(const Capability &c); + void credentialAccepted(const Tag &c); + void credentialAccepted(const Revocation &c); + +private: + const RuntimeEnvironment *const RR; +}; + +} // namespace ZeroTier + +#endif diff --git a/objects.mk b/objects.mk index 3a8bd645..ed396378 100644 --- a/objects.mk +++ b/objects.mk @@ -23,6 +23,7 @@ CORE_OBJS=\ node/Switch.o \ node/Tag.o \ node/Topology.o \ + node/Trace.o \ node/Utils.o ONE_OBJS=\ -- cgit v1.2.3 From 495c5ce81ddb245e21f21325927236d0f666f6cf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 13 Jul 2017 10:51:05 -0700 Subject: Bunch of remote tracing work. --- node/Dictionary.hpp | 29 ++++ node/Identity.cpp | 2 +- node/IncomingPacket.cpp | 180 ++++++++++++------------ node/Membership.cpp | 22 +-- node/Membership.hpp | 5 + node/Network.cpp | 23 ++-- node/Network.hpp | 13 ++ node/Node.cpp | 7 +- node/Node.hpp | 3 + node/Packet.hpp | 5 +- node/Peer.cpp | 9 +- node/Peer.hpp | 4 +- node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 16 +-- node/Trace.cpp | 353 ++++++++++++++++++++++++++++++++++++++++++++---- node/Trace.hpp | 57 ++++---- 16 files changed, 552 insertions(+), 178 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 6cbbfc0e..061dcac1 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -288,6 +288,21 @@ public: return dfl; } + /** + * Get an unsigned int64 stored as hex in the dictionary + * + * @param key Key to look up + * @param dfl Default value or 0 if unspecified + * @return Decoded hex UInt value or 'dfl' if not found + */ + inline int64_t getI(const char *key,int64_t dfl = 0) const + { + char tmp[128]; + if (this->get(key,tmp,sizeof(tmp)) >= 1) + return Utils::hexStrTo64(tmp); + return dfl; + } + /** * Add a new key=value pair * @@ -394,6 +409,20 @@ public: return this->add(key,Utils::hex(value,tmp),-1); } + /** + * Add a 64-bit integer (unsigned) as a hex value + */ + inline bool add(const char *key,int64_t value) + { + char tmp[32]; + if (value >= 0) { + return this->add(key,Utils::hex((uint64_t)value,tmp),-1); + } else { + tmp[0] = '-'; + return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1); + } + } + /** * Add a 64-bit integer (unsigned) as a hex value */ diff --git a/node/Identity.cpp b/node/Identity.cpp index 3b00b4c0..dba27d1c 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -151,7 +151,7 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_ Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p); p += ZT_C25519_PRIVATE_KEY_LEN * 2; } - *(p++) = (char)0; + *p = (char)0; return buf; } diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e1fb180c..a5875d1e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -66,10 +66,10 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // packets are dropped on the floor. const uint64_t tpid = trustedPathId(); if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { - RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,true); + RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,true); trusted = true; } else { - RR->t->incomingPacketTrustedPath(_path,packetId(),sourceAddress,tpid,false); + RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,false); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -82,14 +82,14 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (!trusted) { if (!dearmor(peer->key())) { //fprintf(stderr,"dropped packet from %s(%s), MAC authentication failed (size: %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size()); - RR->t->incomingPacketMessageAuthenticationFailure(_path,packetId(),sourceAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops()); return true; } } if (!uncompress()) { //fprintf(stderr,"dropped packet from %s(%s), compressed data invalid (size %u, verb may be %u)" ZT_EOL_S,sourceAddress.toString().c_str(),_path->address().toString().c_str(),size(),(unsigned int)verb()); - RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"LZ4 decompression failed"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),Packet::VERB_NOP,"LZ4 decompression failed"); return true; } @@ -97,7 +97,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) switch(v) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),v,0,Packet::VERB_NOP,false,0); return true; case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true); @@ -122,7 +122,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) return false; } } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),sourceAddress,Packet::VERB_NOP,"unexpected exception in tryDecode() (outer)"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode() (outer)"); return true; } } @@ -133,6 +133,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; + uint64_t networkId = 0; /* Security note: we do not gate doERROR() with expectingReplyTo() to * avoid having to log every outgoing packet ID. Instead we put the @@ -170,7 +171,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { // Peers can send this in response to frames if they do not have a recent enough COM from us - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); const uint64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(tPtr,peer->address(),now); @@ -186,7 +188,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar case Packet::ERROR_UNWANTED_MULTICAST: { // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); if ((network)&&(network->gate(tPtr,peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); RR->mc->remove(network->id(),mg,peer->address()); @@ -196,9 +199,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar default: break; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ERROR,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_ERROR,"unexpected exception"); } return true; } @@ -219,11 +222,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); if (protoVersion < ZT_PROTO_VERSION_MIN) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"protocol version too old"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"protocol version too old"); return true; } if (fromAddress != id.address()) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"identity/address mismatch"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"identity/address mismatch"); return true; } @@ -241,7 +244,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"address collision"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"address collision"); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); @@ -249,10 +252,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); } } else { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); } return true; @@ -260,7 +263,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); return true; } @@ -272,26 +275,26 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Sanity check: this basically can't happen if (alreadyAuthenticated) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"illegal alreadyAuthenticated state"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"illegal alreadyAuthenticated state"); return true; } // Check rate limits if (!RR->node->rateGateIdentityVerification(now,_path->address())) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"rate limit exceeded"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"rate limit exceeded"); return true; } // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(_path,pid,fromAddress); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); return true; } // Check that identity's address is valid as per the derivation function if (!id.locallyValidate()) { - RR->t->incomingPacketDroppedHELLO(_path,pid,fromAddress,"invalid identity"); + RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"invalid identity"); return true; } @@ -414,9 +417,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_HELLO,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_HELLO,"unexpected exception"); } return true; } @@ -426,6 +429,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + uint64_t networkId = 0; if (!RR->node->expectingReplyTo(inRePacketId)) return true; @@ -491,27 +495,28 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_OK_IDX_PAYLOAD))); + networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); if (network) network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); } break; case Packet::VERB_MULTICAST_GATHER: { - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); + networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(networkId)); if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } } break; case Packet::VERB_MULTICAST_FRAME: { const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); + networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - const SharedPtr network(RR->node->network(nwid)); + const SharedPtr network(RR->node->network(networkId)); if (network) { unsigned int offset = 0; @@ -527,7 +532,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; unsigned int totalKnown = at(offset); offset += 4; unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(tPtr,RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -535,9 +540,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP default: break; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_OK,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_OK,"unexpected exception"); } return true; } @@ -573,9 +578,9 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_WHOIS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_WHOIS,"unexpected exception"); } return true; } @@ -599,9 +604,9 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const } } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_RENDEZVOUS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_RENDEZVOUS,"unexpected exception"); } return true; } @@ -625,14 +630,14 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar } } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true); } } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_FRAME,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_FRAME,"unexpected exception"); } return true; } @@ -654,9 +659,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const } if (!network->gate(tPtr,peer)) { - RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } @@ -668,7 +673,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); if ((!from)||(from == network->mac())) { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } @@ -678,20 +683,20 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } else if (to != network->mac()) { if (to.isMulticast()) { if (network->config().multicastLimit == 0) { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } else if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } @@ -711,12 +716,12 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); } else { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid); } } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_EXT_FRAME,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_EXT_FRAME,"unexpected exception"); } return true; } @@ -736,9 +741,9 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_ECHO,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_ECHO,"unexpected exception"); } return true; } @@ -784,9 +789,9 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_LIKE,"unexpected exception"); } return true; } @@ -803,12 +808,13 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t Revocation revocation; CertificateOfOwnership coo; bool trustEstablished = false; + SharedPtr network; unsigned int p = ZT_PACKET_IDX_PAYLOAD; while ((p < size())&&((*this)[p] != 0)) { p += com.deserialize(*this,p); if (com) { - const SharedPtr network(RR->node->network(com.networkId())); + network = RR->node->network(com.networkId()); if (network) { switch (network->addCredential(tPtr,com)) { case Membership::ADD_REJECTED: @@ -829,7 +835,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numCapabilities = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(cap.networkId())); + if ((!network)||(network->id() != cap.networkId())) + network = RR->node->network(cap.networkId()); if (network) { switch (network->addCredential(tPtr,cap)) { case Membership::ADD_REJECTED: @@ -849,7 +856,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numTags = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(tag.networkId())); + if ((!network)||(network->id() != tag.networkId())) + network = RR->node->network(tag.networkId()); if (network) { switch (network->addCredential(tPtr,tag)) { case Membership::ADD_REJECTED: @@ -869,7 +877,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numRevocations = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(revocation.networkId())); + if ((!network)||(network->id() != revocation.networkId())) + network = RR->node->network(revocation.networkId()); if (network) { switch(network->addCredential(tPtr,peer->address(),revocation)) { case Membership::ADD_REJECTED: @@ -889,7 +898,8 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t const unsigned int numCoos = at(p); p += 2; for(unsigned int i=0;i network(RR->node->network(coo.networkId())); + if ((!network)||(network->id() != coo.networkId())) + network = RR->node->network(coo.networkId()); if (network) { switch(network->addCredential(tPtr,coo)) { case Membership::ADD_REJECTED: @@ -905,9 +915,9 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CREDENTIALS,"unexpected exception"); } return true; } @@ -934,9 +944,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } - peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CONFIG_REQUEST,"unexpected exception"); } return true; } @@ -957,9 +967,9 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_NETWORK_CONFIG,"unexpected exception"); } return true; } @@ -1003,9 +1013,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_GATHER,"unexpected exception"); } return true; } @@ -1030,9 +1040,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } if (!network->gate(tPtr,peer)) { - RR->t->networkAccessDenied(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); + RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true); _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } @@ -1055,20 +1065,20 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); if (network->config().multicastLimit == 0) { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); return true; } if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { if (!to.mac().isMulticast()) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } if ((!from)||(from.isMulticast())||(from == network->mac())) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } @@ -1076,8 +1086,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } else { - RR->t->networkFrameDropped(network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay + RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac()); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay return true; } } @@ -1101,13 +1111,13 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); } else { _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid); } } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"unexpected exception"); } return true; } @@ -1119,7 +1129,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); return true; } @@ -1172,9 +1182,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt ptr += addrLen; } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_PUSH_DIRECT_PATHS,"unexpected exception"); } return true; } @@ -1190,9 +1200,9 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); } - peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false); + peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0); } catch ( ... ) { - RR->t->incomingPacketInvalid(_path,packetId(),source(),Packet::VERB_USER_MESSAGE,"unexpected exception"); + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_USER_MESSAGE,"unexpected exception"); } return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index be6ea6a5..a1453307 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -129,13 +129,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme { const uint64_t newts = com.timestamp(); if (newts <= _comRevocationThreshold) { - RR->t->credentialRejected(com,"revoked"); + RR->t->credentialRejected(tPtr,com,"revoked"); return ADD_REJECTED; } const uint64_t oldts = _com.timestamp(); if (newts < oldts) { - RR->t->credentialRejected(com,"old"); + RR->t->credentialRejected(tPtr,com,"old"); return ADD_REJECTED; } if ((newts == oldts)&&(_com == com)) @@ -143,11 +143,11 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(com.verify(RR,tPtr)) { default: - RR->t->credentialRejected(com,"invalid"); + RR->t->credentialRejected(tPtr,com,"invalid"); return ADD_REJECTED; case 0: _com = com; - RR->t->credentialAccepted(com); + RR->t->credentialAccepted(tPtr,com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -161,7 +161,7 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot C *rc = remoteCreds.get(cred.id()); if (rc) { if (rc->timestamp() > cred.timestamp()) { - RR->t->credentialRejected(cred,"old"); + RR->t->credentialRejected(tPtr,cred,"old"); return Membership::ADD_REJECTED; } if (*rc == cred) @@ -170,16 +170,16 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot const uint64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); if ((rt)&&(*rt >= cred.timestamp())) { - RR->t->credentialRejected(cred,"revoked"); + RR->t->credentialRejected(tPtr,cred,"revoked"); return Membership::ADD_REJECTED; } switch(cred.verify(RR,tPtr)) { default: - RR->t->credentialRejected(cred,"invalid"); + RR->t->credentialRejected(tPtr,cred,"invalid"); return Membership::ADD_REJECTED; case 0: - RR->t->credentialAccepted(cred); + RR->t->credentialAccepted(tPtr,cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -198,14 +198,14 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme uint64_t *rt; switch(rev.verify(RR,tPtr)) { default: - RR->t->credentialRejected(rev,"invalid"); + RR->t->credentialRejected(tPtr,rev,"invalid"); return ADD_REJECTED; case 0: { const Credential::Type ct = rev.type(); switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { - RR->t->credentialAccepted(rev); + RR->t->credentialAccepted(tPtr,rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } @@ -221,7 +221,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } return ADD_ACCEPTED_REDUNDANT; default: - RR->t->credentialRejected(rev,"invalid"); + RR->t->credentialRejected(tPtr,rev,"invalid"); return ADD_REJECTED; } } diff --git a/node/Membership.hpp b/node/Membership.hpp index 5e4475da..c6e2b803 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -110,6 +110,11 @@ public: return nconf.com.agreesWith(_com); } + inline bool recentlyAssociated(const uint64_t now) const + { + return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); + } + /** * Check whether the peer represented by this Membership owns a given resource * diff --git a/node/Network.cpp b/node/Network.cpp index 575b0170..f7b144e3 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -648,7 +648,7 @@ bool Network::filterOutgoingPacket( case DOZTFILTER_DROP: if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -695,16 +695,16 @@ bool Network::filterOutgoingPacket( RR->sw->send(tPtr,outp,true); if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; // DROP locally, since we redirected } else { if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); + RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); return true; } } else { if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); return false; } } @@ -775,7 +775,7 @@ int Network::filterIncomingPacket( case DOZTFILTER_DROP: if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); + RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -816,13 +816,13 @@ int Network::filterIncomingPacket( RR->sw->send(tPtr,outp,true); if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); + RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); return 0; // DROP locally, since we redirected } } if (_config.remoteTraceTarget) - RR->t->networkFilter(*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); + RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); return accept; } @@ -1135,7 +1135,7 @@ void Network::requestConfiguration(void *tPtr) rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); - RR->t->networkConfigRequestSent(*this,ctrl); + RR->t->networkConfigRequestSent(tPtr,*this,ctrl); if (ctrl == RR->identity.address()) { if (RR->localNetworkController) { @@ -1183,6 +1183,13 @@ bool Network::gate(void *tPtr,const SharedPtr &peer) return false; } +bool Network::recentlyAssociatedWith(const Address &addr) +{ + Mutex::Lock _l(_lock); + const Membership *m = _memberships.get(addr); + return ((m)&&(m->recentlyAssociated(RR->node->now()))); +} + void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index 454a3f20..be5f1a12 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -248,6 +248,19 @@ public: */ bool gate(void *tPtr,const SharedPtr &peer); + /** + * Check whether a given peer has recently had an association with this network + * + * This checks whether a peer has communicated with us recently about this + * network and has possessed a valid certificate of membership. This may return + * true even if the peer has been offline for a while or no longer has a valid + * certificate of membership but had one recently. + * + * @param addr Peer address + * @return True if peer has recently associated + */ + bool recentlyAssociatedWith(const Address &addr); + /** * Do periodic cleanup and housekeeping tasks */ diff --git a/node/Node.cpp b/node/Node.cpp index c54ca450..073af4bd 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -90,14 +90,15 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } } - idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; if (n <= 0) { RR->identity.generate(); + idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; RR->identity.toString(false,RR->publicIdentityStr); RR->identity.toString(true,RR->secretIdentityStr); stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr)); stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr)); } else { + idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); if (n > 0) { tmp[n] = (char)0; @@ -201,7 +202,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now,0); contacted = true; break; } @@ -211,7 +212,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(_tPtr,InetAddress(),addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now,0); contacted = true; break; } diff --git a/node/Node.hpp b/node/Node.hpp index 57b99fe9..e60da1ad 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -257,6 +257,8 @@ public: virtual void ncSendRevocation(const Address &destination,const Revocation &rev); virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); + inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; } + private: RuntimeEnvironment _RR; RuntimeEnvironment *RR; @@ -278,6 +280,7 @@ private: Mutex _backgroundTasksLock; + Address _remoteTraceTarget; uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; diff --git a/node/Packet.hpp b/node/Packet.hpp index 4941e96a..a1ea73e1 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -967,9 +967,8 @@ public: /** * A trace for remote debugging or diagnostics: - * <[8] 64-bit instance ID> - * <[2] 16-bit length of Dictionary> - * <[...] dictionary containing trace information> + * <[...] null-terminated dictionary containing trace information> + * [<[...] additional null-terminated dictionaries>] * * This message contains a remote trace event. Remote trace events can * be sent to observers configured at the network level for those that diff --git a/node/Peer.cpp b/node/Peer.cpp index 79a4bc90..d362be9f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -72,7 +72,8 @@ void Peer::received( const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished) + const bool trustEstablished, + const uint64_t networkId) { const uint64_t now = RR->node->now(); @@ -183,11 +184,11 @@ void Peer::received( if (replacablePath) { if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(*this,replacablePath->p,path,packetId); + RR->t->peerLearnedNewPath(tPtr,networkId,*this,replacablePath->p,path,packetId); replacablePath->lr = now; replacablePath->p = path; } else { - RR->t->peerConfirmingUnknownPath(*this,path,packetId,verb); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); path->sent(now); } @@ -438,7 +439,7 @@ void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remo } } - RR->t->peerRedirected(*this,op,np); + RR->t->peerRedirected(tPtr,0,*this,op,np); } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index b24318ec..6d00e3e6 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -102,6 +102,7 @@ public: * @param inRePacketId Packet ID in reply to (default: none) * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established + * @param networkId Network ID if this pertains to a network, or 0 otherwise */ void received( void *tPtr, @@ -111,7 +112,8 @@ public: const Packet::Verb verb, const uint64_t inRePacketId, const Packet::Verb inReVerb, - const bool trustEstablished); + const bool trustEstablished, + const uint64_t networkId); /** * @param now Current time diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 173230fb..cdbb6303 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -82,7 +82,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { // Changes to external surface reported by trusted peers causes path reset in this scope - RR->t->resettingPathsInScope(reporter,reporterPhysicalAddress,myPhysicalAddress,scope); + RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope); entry.mySurface = myPhysicalAddress; entry.ts = now; diff --git a/node/Switch.cpp b/node/Switch.cpp index 2fbd243b..eee49775 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -318,7 +318,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const bool fromBridged; if ((fromBridged = (from != network->mac()))) { if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"not a bridge"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"not a bridge"); return; } } @@ -340,7 +340,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"broadcast disabled"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"broadcast disabled"); return; } } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { @@ -428,7 +428,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // Check this after NDP emulation, since that has to be allowed in exactly this case if (network->config().multicastLimit == 0) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"multicast disabled"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"multicast disabled"); return; } @@ -441,7 +441,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -467,7 +467,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -499,7 +499,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // for each ZT destination are also done below. This is the same rationale // and design as for multicast. if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); return; } @@ -548,7 +548,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const outp.compress(); send(tPtr,outp,true); } else { - RR->t->outgoingFrameDropped(network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); + RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); } } } @@ -646,7 +646,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) if (_trySend(tPtr,txi->packet,txi->encrypt)) _txQueue.erase(txi++); else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - RR->t->txTimedOut(txi->dest); + RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); } else ++txi; } diff --git a/node/Trace.cpp b/node/Trace.cpp index 6b68cfe7..dc5ecf19 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -29,16 +29,25 @@ #include "Switch.hpp" #include "Node.hpp" #include "Utils.hpp" +#include "Dictionary.hpp" +#include "CertificateOfMembership.hpp" +#include "CertificateOfOwnership.hpp" +#include "CertificateOfRepresentation.hpp" +#include "Tag.hpp" +#include "Capability.hpp" +#include "Revocation.hpp" namespace ZeroTier { +// Defining ZT_TRACE causes debug tracing messages to be dumped to stderr #ifdef ZT_TRACE + static const char *packetVerbString(Packet::Verb v) { switch(v) { case Packet::VERB_NOP: return "NOP"; case Packet::VERB_HELLO: return "HELLO"; - case Packet::Packet::VERB_ERROR: return "ERROR"; + case Packet::VERB_ERROR: return "ERROR"; case Packet::VERB_OK: return "OK"; case Packet::VERB_WHOIS: return "WHOIS"; case Packet::VERB_RENDEZVOUS: return "RENDEZVOUS"; @@ -73,61 +82,220 @@ static const char *packetErrorString(Packet::ErrorCode e) } return "(unknown)"; } -#endif -void Trace::resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) +#define TRprintf(f,...) { fprintf(stderr,(f),__VA_ARGS__); fflush(stderr); } + +#else + +#define TRprintf(f,...) + +#endif // ZT_TRACE + +#define ZT_REMOTE_TRACE_FIELD__EVENT "E" +#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "pid" +#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "pv" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "ptpid" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "ptpok" +#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "phops" +#define ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR "oldrphy" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "rzt" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "rphy" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "lzt" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "lphy" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "ls" +#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "ipsc" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "nwid" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "seth" +#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "deth" +#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "et" +#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlan" +#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "fl" +#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "fd" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credtype" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credid" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credts" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credinfo" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "crediss" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRt" +#define ZT_REMOTE_TRACE_FIELD__REASON "reason" + +#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" +#define ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT_S "1001" +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1002" +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1003" +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1004" +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1005" +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1006" +#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" + +#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" + +void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,reporter); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,reporterPhysicalAddress.toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope); + _send(tPtr,d,0); } -void Trace::txTimedOut(const Address &destination) +void Trace::txTimedOut(void *const tPtr,const Address &destination) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT_S); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,destination); + _send(tPtr,d,0); } -void Trace::peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) +void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + _send(tPtr,d,networkId); } -void Trace::peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) +void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (oldPath) { + d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); + } + if (newPath) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + } + _send(tPtr,d,networkId); } -void Trace::peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) +void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (oldPath) { + d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); + } + if (newPath) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + } + _send(tPtr,d,networkId); } -void Trace::outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) +void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) { + if (!network) return; // sanity check + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,network); } -void Trace::incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) +void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) { + if (!network) return; // sanity check + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } } -void Trace::incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source) +void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) { + //Dictionary d; + //d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); } -void Trace::incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason) +void Trace::incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) { + // TODO } -void Trace::incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) +void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + _send(tPtr,d,0); } -void Trace::networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) +void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,0); } -void Trace::networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac) +void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) { + char tmp[128]; + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + _send(tPtr,d,0); } -void Trace::networkConfigRequestSent(const Network &network,const Address &controller) +void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller) { } void Trace::networkFilter( + void *const tPtr, const Network &network, const RuleResultLog &primaryRuleSetLog, const RuleResultLog *const matchingCapabilityRuleSetLog, @@ -144,54 +312,185 @@ void Trace::networkFilter( const bool inbound, const int accept) { + //char tmp[128]; + //Dictionary d; + //_send(tPtr,d,network.id()); +} + +void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) +{ + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const CertificateOfMembership &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const CertificateOfOwnership &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const CertificateOfRepresentation &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const Capability &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const Tag &c,const char *reason) +void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); } -void Trace::credentialRejected(const Revocation &c,const char *reason) +void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); } -void Trace::credentialAccepted(const CertificateOfMembership &c) +void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); } -void Trace::credentialAccepted(const CertificateOfOwnership &c) +void Trace::credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); } -void Trace::credentialAccepted(const CertificateOfRepresentation &c) +void Trace::credentialAccepted(void *const tPtr,const Capability &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); } -void Trace::credentialAccepted(const Capability &c) +void Trace::credentialAccepted(void *const tPtr,const Tag &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); } -void Trace::credentialAccepted(const Tag &c) +void Trace::credentialAccepted(void *const tPtr,const Revocation &c) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); } -void Trace::credentialAccepted(const Revocation &c) +void Trace::_send(void *const tPtr,const Dictionary &d) { + const Address rtt(RR->node->remoteTraceTarget()); + if (rtt) { + Packet outp(rtt,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); + } +} + +void Trace::_send(void *const tPtr,const Dictionary &d,const uint64_t networkId) +{ + _send(tPtr,d); + if (networkId) { + const SharedPtr network(RR->node->network(networkId)); + if ((network)&&(network->config().remoteTraceTarget)) { + Packet outp(network->config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); + } + } +} + +void Trace::_send(void *const tPtr,const Dictionary &d,const SharedPtr &network) +{ + _send(tPtr,d); + if ((network)&&(network->config().remoteTraceTarget)) { + Packet outp(network->config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); + } } } // namespace ZeroTier diff --git a/node/Trace.hpp b/node/Trace.hpp index 65d1acf1..eefd5359 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -39,6 +39,7 @@ #include "Packet.hpp" #include "Credential.hpp" #include "InetAddress.hpp" +#include "Dictionary.hpp" namespace ZeroTier { @@ -100,25 +101,25 @@ public: Trace(const RuntimeEnvironment *renv) : RR(renv) {} - void resettingPathsInScope(const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); - void txTimedOut(const Address &destination); + void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); + void txTimedOut(void *const tPtr,const Address &destination); - void peerConfirmingUnknownPath(Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); - void peerLearnedNewPath(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); - void peerRedirected(Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); + void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); + void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); + void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); - void outgoingFrameDropped(const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); + void incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); + void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops); + void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); + void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); - void incomingPacketTrustedPath(const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); - void incomingPacketMessageAuthenticationFailure(const SharedPtr &path,const uint64_t packetId,const Address &source); - void incomingPacketInvalid(const SharedPtr &path,const uint64_t packetId,const Address &source,const Packet::Verb verb,const char *reason); - void incomingPacketDroppedHELLO(const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); + void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); + void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); + void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); - void networkAccessDenied(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); - void networkFrameDropped(const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac); - - void networkConfigRequestSent(const Network &network,const Address &controller); + void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller); void networkFilter( + void *const tPtr, const Network &network, const RuleResultLog &primaryRuleSetLog, const RuleResultLog *const matchingCapabilityRuleSetLog, @@ -135,21 +136,25 @@ public: const bool inbound, const int accept); - void credentialRejected(const CertificateOfMembership &c,const char *reason); - void credentialRejected(const CertificateOfOwnership &c,const char *reason); - void credentialRejected(const CertificateOfRepresentation &c,const char *reason); - void credentialRejected(const Capability &c,const char *reason); - void credentialRejected(const Tag &c,const char *reason); - void credentialRejected(const Revocation &c,const char *reason); - void credentialAccepted(const CertificateOfMembership &c); - void credentialAccepted(const CertificateOfOwnership &c); - void credentialAccepted(const CertificateOfRepresentation &c); - void credentialAccepted(const Capability &c); - void credentialAccepted(const Tag &c); - void credentialAccepted(const Revocation &c); + void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason); + void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason); + void credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason); + void credentialRejected(void *const tPtr,const Capability &c,const char *reason); + void credentialRejected(void *const tPtr,const Tag &c,const char *reason); + void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); + void credentialAccepted(void *const tPtr,const CertificateOfMembership &c); + void credentialAccepted(void *const tPtr,const CertificateOfOwnership &c); + void credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c); + void credentialAccepted(void *const tPtr,const Capability &c); + void credentialAccepted(void *const tPtr,const Tag &c); + void credentialAccepted(void *const tPtr,const Revocation &c); private: const RuntimeEnvironment *const RR; + + void _send(void *const tPtr,const Dictionary &d); + void _send(void *const tPtr,const Dictionary &d,const uint64_t networkId); + void _send(void *const tPtr,const Dictionary &d,const SharedPtr &network); }; } // namespace ZeroTier -- cgit v1.2.3 From b9e1d53d7ac4e8d19520e3063b194ee01f550198 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 17 Jul 2017 14:21:09 -0700 Subject: Minor cleanup. --- node/Array.hpp | 60 +++++++++++++++++++----------------- node/Buffer.hpp | 42 ++++++++++++------------- node/C25519.cpp | 5 --- node/C25519.hpp | 32 +++++-------------- node/Capability.hpp | 10 +++--- node/CertificateOfMembership.hpp | 8 ++--- node/CertificateOfOwnership.hpp | 4 +-- node/CertificateOfRepresentation.hpp | 4 +-- node/Constants.hpp | 9 ++++++ node/Hashtable.hpp | 8 ++--- node/Identity.cpp | 5 ++- node/Identity.hpp | 29 +++++++++-------- node/IncomingPacket.hpp | 2 +- node/InetAddress.hpp | 2 +- node/MAC.hpp | 2 +- node/MulticastGroup.hpp | 25 +++++++-------- node/Multicaster.hpp | 4 +-- node/Mutex.hpp | 22 +++---------- node/Network.hpp | 4 +-- node/NetworkConfig.hpp | 14 ++++----- node/Node.cpp | 2 +- node/Node.hpp | 4 +-- node/NonCopyable.hpp | 2 +- node/OutboundMulticast.hpp | 6 ++-- node/Packet.hpp | 9 ++---- node/Peer.cpp | 2 +- node/Peer.hpp | 4 +-- node/Poly1305.cpp | 2 -- node/Poly1305.hpp | 3 +- node/Revocation.hpp | 4 +-- node/Switch.hpp | 4 +-- node/Tag.hpp | 4 +-- node/World.hpp | 12 ++++---- 33 files changed, 155 insertions(+), 194 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Array.hpp b/node/Array.hpp index 5c616475..ef2611e4 100644 --- a/node/Array.hpp +++ b/node/Array.hpp @@ -27,7 +27,6 @@ #ifndef ZT_ARRAY_HPP #define ZT_ARRAY_HPP -#include #include namespace ZeroTier { @@ -39,23 +38,23 @@ template class Array { public: - Array() throw() {} + Array() {} Array(const Array &a) { - for(std::size_t i=0;i reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - inline iterator begin() throw() { return data; } - inline iterator end() throw() { return &(data[S]); } - inline const_iterator begin() const throw() { return data; } - inline const_iterator end() const throw() { return &(data[S]); } + inline iterator begin() { return data; } + inline iterator end() { return &(data[S]); } + inline const_iterator begin() const { return data; } + inline const_iterator end() const { return &(data[S]); } - inline reverse_iterator rbegin() throw() { return reverse_iterator(begin()); } - inline reverse_iterator rend() throw() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const throw() { return const_reverse_iterator(begin()); } - inline const_reverse_iterator rend() const throw() { return const_reverse_iterator(end()); } + inline reverse_iterator rbegin() { return reverse_iterator(begin()); } + inline reverse_iterator rend() { return reverse_iterator(end()); } + inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } + inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } + */ - inline std::size_t size() const throw() { return S; } - inline std::size_t max_size() const throw() { return S; } + inline unsigned long size() const { return S; } + inline unsigned long max_size() const { return S; } - inline reference operator[](const std::size_t n) throw() { return data[n]; } - inline const_reference operator[](const std::size_t n) const throw() { return data[n]; } + inline reference operator[](const std::size_t n) { return data[n]; } + inline const_reference operator[](const std::size_t n) const { return data[n]; } - inline reference front() throw() { return data[0]; } - inline const_reference front() const throw() { return data[0]; } - inline reference back() throw() { return data[S-1]; } - inline const_reference back() const throw() { return data[S-1]; } + inline reference front() { return data[0]; } + inline const_reference front() const { return data[0]; } + inline reference back() { return data[S-1]; } + inline const_reference back() const { return data[S-1]; } - inline bool operator==(const Array &k) const throw() + inline bool operator==(const Array &k) const { for(unsigned long i=0;i(const Array &k) const throw() { return (k < *this); } - inline bool operator<=(const Array &k) const throw() { return !(k < *this); } - inline bool operator>=(const Array &k) const throw() { return !(*this < k); } + inline bool operator!=(const Array &k) const { return !(*this == k); } + inline bool operator<(const Array &k) const { return std::lexicographical_compare(data,data + S,k.data,k.data + S); } + inline bool operator>(const Array &k) const { return (k < *this); } + inline bool operator<=(const Array &k) const { return !(k < *this); } + inline bool operator>=(const Array &k) const { return !(*this < k); } T data[S]; }; diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 69ee1758..8979938f 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -95,7 +95,7 @@ public: Buffer(unsigned int l) { if (l > C) - throw std::out_of_range("Buffer: construct with size larger than capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; _l = l; } @@ -119,7 +119,7 @@ public: inline Buffer &operator=(const Buffer &b) { if (unlikely(b._l > C)) - throw std::out_of_range("Buffer: assignment from buffer larger than capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; if (C2 == C) { memcpy(this,&b,sizeof(Buffer)); } else { @@ -131,7 +131,7 @@ public: inline void copyFrom(const void *b,unsigned int l) { if (unlikely(l > C)) - throw std::out_of_range("Buffer: set from C array larger than capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; memcpy(_b,b,l); _l = l; } @@ -139,14 +139,14 @@ public: unsigned char operator[](const unsigned int i) const { if (unlikely(i >= _l)) - throw std::out_of_range("Buffer: [] beyond end of data"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; return (unsigned char)_b[i]; } unsigned char &operator[](const unsigned int i) { if (unlikely(i >= _l)) - throw std::out_of_range("Buffer: [] beyond end of data"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; return ((unsigned char *)_b)[i]; } @@ -166,13 +166,13 @@ public: unsigned char *field(unsigned int i,unsigned int l) { if (unlikely((i + l) > _l)) - throw std::out_of_range("Buffer: field() beyond end of data"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; return (unsigned char *)(_b + i); } const unsigned char *field(unsigned int i,unsigned int l) const { if (unlikely((i + l) > _l)) - throw std::out_of_range("Buffer: field() beyond end of data"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; return (const unsigned char *)(_b + i); } @@ -187,7 +187,7 @@ public: inline void setAt(unsigned int i,const T v) { if (unlikely((i + sizeof(T)) > _l)) - throw std::out_of_range("Buffer: setAt() beyond end of data"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; #ifdef ZT_NO_TYPE_PUNNING uint8_t *p = reinterpret_cast(_b + i); for(unsigned int x=1;x<=sizeof(T);++x) @@ -209,7 +209,7 @@ public: inline T at(unsigned int i) const { if (unlikely((i + sizeof(T)) > _l)) - throw std::out_of_range("Buffer: at() beyond end of data"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; #ifdef ZT_NO_TYPE_PUNNING T v = 0; const uint8_t *p = reinterpret_cast(_b + i); @@ -235,7 +235,7 @@ public: inline void append(const T v) { if (unlikely((_l + sizeof(T)) > C)) - throw std::out_of_range("Buffer: append beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; #ifdef ZT_NO_TYPE_PUNNING uint8_t *p = reinterpret_cast(_b + _l); for(unsigned int x=1;x<=sizeof(T);++x) @@ -257,7 +257,7 @@ public: inline void append(unsigned char c,unsigned int n) { if (unlikely((_l + n) > C)) - throw std::out_of_range("Buffer: append beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; for(unsigned int i=0;i C)) - throw std::out_of_range("Buffer: append beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; Utils::getSecureRandom(_b + _l,n); _l += n; } @@ -285,7 +285,7 @@ public: inline void append(const void *b,unsigned int l) { if (unlikely((_l + l) > C)) - throw std::out_of_range("Buffer: append beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; memcpy(_b + _l,b,l); _l += l; } @@ -311,7 +311,7 @@ public: { for(;;) { if (unlikely(_l >= C)) - throw std::out_of_range("Buffer: append beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; if (!(_b[_l++] = *(s++))) break; } @@ -343,7 +343,7 @@ public: inline char *appendField(unsigned int l) { if (unlikely((_l + l) > C)) - throw std::out_of_range("Buffer: append beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; char *r = _b + _l; _l += l; return r; @@ -360,7 +360,7 @@ public: inline void addSize(unsigned int i) { if (unlikely((i + _l) > C)) - throw std::out_of_range("Buffer: setSize to larger than capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; _l += i; } @@ -375,7 +375,7 @@ public: inline void setSize(const unsigned int i) { if (unlikely(i > C)) - throw std::out_of_range("Buffer: setSize to larger than capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; _l = i; } @@ -383,14 +383,14 @@ public: * Move everything after 'at' to the buffer's front and truncate * * @param at Truncate before this position - * @throw std::out_of_range Position is beyond size of buffer + * @throws std::out_of_range Position is beyond size of buffer */ inline void behead(const unsigned int at) { if (!at) return; if (unlikely(at > _l)) - throw std::out_of_range("Buffer: behead() beyond capacity"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; ::memmove(_b,_b + at,_l -= at); } @@ -399,13 +399,13 @@ public: * * @param start Starting position * @param length Length of block to erase - * @throw std::out_of_range Position plus length is beyond size of buffer + * @throws std::out_of_range Position plus length is beyond size of buffer */ inline void erase(const unsigned int at,const unsigned int length) { const unsigned int endr = at + length; if (unlikely(endr > _l)) - throw std::out_of_range("Buffer: erase() range beyond end of buffer"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; ::memmove(_b + at,_b + endr,_l - endr); _l -= length; } diff --git a/node/C25519.cpp b/node/C25519.cpp index 4158f1ba..2a5575aa 100644 --- a/node/C25519.cpp +++ b/node/C25519.cpp @@ -1998,7 +1998,6 @@ static inline void get_hram(unsigned char *hram, const unsigned char *sm, const ////////////////////////////////////////////////////////////////////////////// void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void *keybuf,unsigned int keylen) - throw() { unsigned char rawkey[32]; unsigned char digest[64]; @@ -2015,7 +2014,6 @@ void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void } void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature) - throw() { sc25519 sck, scs, scsk; ge25519 ger; @@ -2065,7 +2063,6 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli } bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len,const void *signature) - throw() { unsigned char t2[32]; ge25519 get1, get2; @@ -2096,7 +2093,6 @@ bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len } void C25519::_calcPubDH(C25519::Pair &kp) - throw() { // First 32 bytes of pub and priv are the keys for ECDH key // agreement. This generates the public portion from the private. @@ -2104,7 +2100,6 @@ void C25519::_calcPubDH(C25519::Pair &kp) } void C25519::_calcPubED(C25519::Pair &kp) - throw() { unsigned char extsk[64]; sc25519 scsk; diff --git a/node/C25519.hpp b/node/C25519.hpp index da9ba665..950c7fed 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -69,7 +69,6 @@ public: * Generate a C25519 elliptic curve key pair */ static inline Pair generate() - throw() { Pair kp; Utils::getSecureRandom(kp.priv.data,(unsigned int)kp.priv.size()); @@ -93,7 +92,6 @@ public: */ template static inline Pair generateSatisfying(F cond) - throw() { Pair kp; void *const priv = (void *)kp.priv.data; @@ -118,13 +116,8 @@ public: * @param keybuf Buffer to fill * @param keylen Number of key bytes to generate */ - static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen) - throw(); - static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) - throw() - { - agree(mine.priv,their,keybuf,keylen); - } + static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen); + static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); } /** * Sign a message with a sender's key pair @@ -145,13 +138,8 @@ public: * @param len Length of message in bytes * @param signature Buffer to fill with signature -- MUST be 96 bytes in length */ - static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature) - throw(); - static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) - throw() - { - sign(mine.priv,mine.pub,msg,len,signature); - } + static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature); + static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); } /** * Sign a message with a sender's key pair @@ -163,14 +151,12 @@ public: * @return Signature */ static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len) - throw() { Signature sig; sign(myPrivate,myPublic,msg,len,sig.data); return sig; } static inline Signature sign(const Pair &mine,const void *msg,unsigned int len) - throw() { Signature sig; sign(mine.priv,mine.pub,msg,len,sig.data); @@ -186,8 +172,7 @@ public: * @param signature 96-byte signature * @return True if signature is valid and the message is authentic and unmodified */ - static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature) - throw(); + static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature); /** * Verify a message's signature @@ -199,7 +184,6 @@ public: * @return True if signature is valid and the message is authentic and unmodified */ static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature) - throw() { return verify(their,msg,len,signature.data); } @@ -207,13 +191,11 @@ public: private: // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv // this is the ECDH key - static void _calcPubDH(Pair &kp) - throw(); + static void _calcPubDH(Pair &kp); // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv // this is the Ed25519 sign/verify key - static void _calcPubED(Pair &kp) - throw(); + static void _calcPubED(Pair &kp); }; } // namespace ZeroTier diff --git a/node/Capability.hpp b/node/Capability.hpp index 8d4b9085..d64625e6 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -420,24 +420,24 @@ public: const unsigned int rc = b.template at(p); p += 2; if (rc > ZT_MAX_CAPABILITY_RULES) - throw std::runtime_error("rule overflow"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; deserializeRules(b,p,_rules,_ruleCount,rc); _maxCustodyChainLength = (unsigned int)b[p++]; if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) - throw std::runtime_error("invalid max custody chain length"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; for(unsigned int i=0;;++i) { const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (!to) break; if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) - throw std::runtime_error("unterminated custody chain"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; _custody[i].to = to; _custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (b[p++] == 1) { if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; p += 2; memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; } else { @@ -447,7 +447,7 @@ public: p += 2 + b.template at(p); if (p > b.size()) - throw std::runtime_error("extended field overflow"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; return (p - startAt); } diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 739d5390..3ffa814f 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -305,14 +305,14 @@ public: _signedBy.zero(); if (b[p++] != 1) - throw std::invalid_argument("invalid object"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; unsigned int numq = b.template at(p); p += sizeof(uint16_t); uint64_t lastId = 0; for(unsigned int i=0;i(p); if (qid < lastId) - throw std::invalid_argument("qualifiers not sorted"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; else lastId = qid; if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { _qualifiers[_qualifierCount].id = qid; @@ -321,7 +321,7 @@ public: p += 24; ++_qualifierCount; } else { - throw std::invalid_argument("too many qualifiers"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; } } @@ -359,7 +359,7 @@ private: uint64_t id; uint64_t value; uint64_t maxDelta; - inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // sort order + inline bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order }; Address _signedBy; diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 95039a2d..775324e6 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -207,7 +207,7 @@ public: _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (b[p++] == 1) { if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature length"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; p += 2; memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; } else { @@ -216,7 +216,7 @@ public: p += 2 + b.template at(p); if (p > b.size()) - throw std::runtime_error("extended field overflow"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; return (p - startAt); } diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp index 92a71bc0..3007f1dc 100644 --- a/node/CertificateOfRepresentation.hpp +++ b/node/CertificateOfRepresentation.hpp @@ -164,14 +164,14 @@ public: p += 2; memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - } else throw std::runtime_error("invalid signature"); + } else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; } else { p += 2 + b.template at(p); } p += 2 + b.template at(p); if (p > b.size()) - throw std::runtime_error("extended field overflow"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; return (p - startAt); } diff --git a/node/Constants.hpp b/node/Constants.hpp index 12bf8d28..3f050ead 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -478,4 +478,13 @@ #define ZT_ETHERTYPE_IPX_B 0x8138 #define ZT_ETHERTYPE_IPV6 0x86dd +#define ZT_EXCEPTION_OUT_OF_BOUNDS 100 +#define ZT_EXCEPTION_OUT_OF_MEMORY 101 +#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102 +#define ZT_EXCEPTION_INVALID_ARGUMENT 103 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203 + #endif diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index b702f608..eff5b62a 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -119,7 +119,7 @@ public: _s(0) { if (!_t) - throw std::bad_alloc(); + throw ZT_EXCEPTION_OUT_OF_MEMORY; for(unsigned long i=0;i diff --git a/node/Identity.cpp b/node/Identity.cpp index a972d60d..72bea75d 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -83,10 +83,9 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub // threshold value. struct _Identity_generate_cond { - _Identity_generate_cond() throw() {} - _Identity_generate_cond(unsigned char *sb,char *gm) throw() : digest(sb),genmem(gm) {} + _Identity_generate_cond() {} + _Identity_generate_cond(unsigned char *sb,char *gm) : digest(sb),genmem(gm) {} inline bool operator()(const C25519::Pair &kp) const - throw() { _computeMemoryHardHash(kp.pub.data,(unsigned int)kp.pub.size(),digest,genmem); return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN); diff --git a/node/Identity.hpp b/node/Identity.hpp index 5804b9f8..3d4d9385 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -71,7 +71,7 @@ public: _privateKey((C25519::Private *)0) { if (!fromString(str)) - throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; } template @@ -121,7 +121,7 @@ public: /** * @return True if this identity contains a private key */ - inline bool hasPrivate() const throw() { return (_privateKey != (C25519::Private *)0); } + inline bool hasPrivate() const { return (_privateKey != (C25519::Private *)0); } /** * Compute the SHA512 hash of our private key (if we have one) @@ -145,11 +145,10 @@ public: * @param len Length of data */ inline C25519::Signature sign(const void *data,unsigned int len) const - throw(std::runtime_error) { if (_privateKey) return C25519::sign(*_privateKey,_publicKey,data,len); - throw std::runtime_error("sign() requires a private key"); + throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED; } /** @@ -203,7 +202,7 @@ public: /** * @return This identity's address */ - inline const Address &address() const throw() { return _address; } + inline const Address &address() const { return _address; } /** * Serialize this identity (binary) @@ -248,7 +247,7 @@ public: p += ZT_ADDRESS_LENGTH; if (b[p++] != 0) - throw std::invalid_argument("unsupported identity type"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; memcpy(_publicKey.data,b.field(p,(unsigned int)_publicKey.size()),(unsigned int)_publicKey.size()); p += (unsigned int)_publicKey.size(); @@ -256,7 +255,7 @@ public: unsigned int privateKeyLength = (unsigned int)b[p++]; if (privateKeyLength) { if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN) - throw std::invalid_argument("invalid private key"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; _privateKey = new C25519::Private(); memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN); p += ZT_C25519_PRIVATE_KEY_LEN; @@ -306,14 +305,14 @@ public: /** * @return True if this identity contains something */ - inline operator bool() const throw() { return (_address); } - - inline bool operator==(const Identity &id) const throw() { return ((_address == id._address)&&(_publicKey == id._publicKey)); } - inline bool operator<(const Identity &id) const throw() { return ((_address < id._address)||((_address == id._address)&&(_publicKey < id._publicKey))); } - inline bool operator!=(const Identity &id) const throw() { return !(*this == id); } - inline bool operator>(const Identity &id) const throw() { return (id < *this); } - inline bool operator<=(const Identity &id) const throw() { return !(id < *this); } - inline bool operator>=(const Identity &id) const throw() { return !(*this < id); } + inline operator bool() const { return (_address); } + + inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(_publicKey == id._publicKey)); } + inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(_publicKey < id._publicKey))); } + inline bool operator!=(const Identity &id) const { return !(*this == id); } + inline bool operator>(const Identity &id) const { return (id < *this); } + inline bool operator<=(const Identity &id) const { return !(id < *this); } + inline bool operator>=(const Identity &id) const { return !(*this < id); } private: Address _address; diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 692c63df..45a0166d 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -118,7 +118,7 @@ public: /** * @return Time of packet receipt / start of decode */ - inline uint64_t receiveTime() const throw() { return _receiveTime; } + inline uint64_t receiveTime() const { return _receiveTime; } private: // These are called internally to handle packet contents once it has diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index dd055084..61cdb05e 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -521,7 +521,7 @@ struct InetAddress : public sockaddr_storage reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); p += 2; break; default: - throw std::invalid_argument("invalid serialized InetAddress"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; } return (p - startAt); } diff --git a/node/MAC.hpp b/node/MAC.hpp index 52388d59..a179fd4f 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -191,7 +191,7 @@ public: * @param i Value from 0 to 5 (inclusive) * @return Byte at said position (address interpreted in big-endian order) */ - inline unsigned char operator[](unsigned int i) const throw() { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); } + inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); } /** * @return 6, which is the number of bytes in a MAC, for container compliance diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index f56c675b..6039d3c4 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -52,15 +52,13 @@ namespace ZeroTier { class MulticastGroup { public: - MulticastGroup() - throw() : + MulticastGroup() : _mac(), _adi(0) { } - MulticastGroup(const MAC &m,uint32_t a) - throw() : + MulticastGroup(const MAC &m,uint32_t a) : _mac(m), _adi(a) { @@ -73,7 +71,6 @@ public: * @return Multicat group for ARP/NDP */ static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) - throw() { if (ip.isV4()) { // IPv4 wants broadcast MACs, so we shove the V4 address itself into @@ -95,18 +92,18 @@ public: /** * @return Multicast address */ - inline const MAC &mac() const throw() { return _mac; } + inline const MAC &mac() const { return _mac; } /** * @return Additional distinguishing information */ - inline uint32_t adi() const throw() { return _adi; } + inline uint32_t adi() const { return _adi; } - inline unsigned long hashCode() const throw() { return (_mac.hashCode() ^ (unsigned long)_adi); } + inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); } - inline bool operator==(const MulticastGroup &g) const throw() { return ((_mac == g._mac)&&(_adi == g._adi)); } - inline bool operator!=(const MulticastGroup &g) const throw() { return ((_mac != g._mac)||(_adi != g._adi)); } - inline bool operator<(const MulticastGroup &g) const throw() + inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); } + inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); } + inline bool operator<(const MulticastGroup &g) const { if (_mac < g._mac) return true; @@ -114,9 +111,9 @@ public: return (_adi < g._adi); return false; } - inline bool operator>(const MulticastGroup &g) const throw() { return (g < *this); } - inline bool operator<=(const MulticastGroup &g) const throw() { return !(g < *this); } - inline bool operator>=(const MulticastGroup &g) const throw() { return !(*this < g); } + inline bool operator>(const MulticastGroup &g) const { return (g < *this); } + inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); } + inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); } private: MAC _mac; diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 2186e9c3..69a6645d 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -64,8 +64,8 @@ private: uint64_t nwid; MulticastGroup mg; - inline bool operator==(const Key &k) const throw() { return ((nwid == k.nwid)&&(mg == k.mg)); } - inline unsigned long hashCode() const throw() { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); } + inline bool operator==(const Key &k) const { return ((nwid == k.nwid)&&(mg == k.mg)); } + inline unsigned long hashCode() const { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); } }; struct MulticastGroupMember diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 6f1d3471..854f321a 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -41,7 +41,6 @@ class Mutex : NonCopyable { public: Mutex() - throw() { pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); } @@ -52,25 +51,21 @@ public: } inline void lock() - throw() { pthread_mutex_lock(&_mh); } inline void unlock() - throw() { pthread_mutex_unlock(&_mh); } inline void lock() const - throw() { (const_cast (this))->lock(); } inline void unlock() const - throw() { (const_cast (this))->unlock(); } @@ -81,15 +76,13 @@ public: class Lock : NonCopyable { public: - Lock(Mutex &m) - throw() : + Lock(Mutex &m) : _m(&m) { m.lock(); } - Lock(const Mutex &m) - throw() : + Lock(const Mutex &m) : _m(const_cast(&m)) { _m->lock(); @@ -123,7 +116,6 @@ class Mutex : NonCopyable { public: Mutex() - throw() { InitializeCriticalSection(&_cs); } @@ -134,25 +126,21 @@ public: } inline void lock() - throw() { EnterCriticalSection(&_cs); } inline void unlock() - throw() { LeaveCriticalSection(&_cs); } inline void lock() const - throw() { (const_cast (this))->lock(); } inline void unlock() const - throw() { (const_cast (this))->unlock(); } @@ -160,15 +148,13 @@ public: class Lock : NonCopyable { public: - Lock(Mutex &m) - throw() : + Lock(Mutex &m) : _m(&m) { m.lock(); } - Lock(const Mutex &m) - throw() : + Lock(const Mutex &m) : _m(const_cast(&m)) { _m->lock(); diff --git a/node/Network.hpp b/node/Network.hpp index be5f1a12..d4d217f2 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -76,7 +76,7 @@ public: /** * Compute primary controller device ID from network ID */ - static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); } + static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); } /** * Construct a new network @@ -98,7 +98,7 @@ public: inline Address controller() const { return Address(_id >> 24); } inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } inline bool hasConfig() const { return (_config); } - inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; } + inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } inline const NetworkConfig &config() const { return _config; } inline const MAC &mac() const { return _mac; } diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 8b3b3619..fb48edc9 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -262,32 +262,32 @@ public: /** * @return True if passive bridging is allowed (experimental) */ - inline bool allowPassiveBridging() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0); } + inline bool allowPassiveBridging() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0); } /** * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network */ - inline bool enableBroadcast() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } + inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } /** * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns */ - inline bool ndpEmulation() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } + inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } /** * @return True if frames should not be compressed */ - inline bool disableCompression() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); } + inline bool disableCompression() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); } /** * @return Network type is public (no access control) */ - inline bool isPublic() const throw() { return (this->type == ZT_NETWORK_TYPE_PUBLIC); } + inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); } /** * @return Network type is private (certificate access control) */ - inline bool isPrivate() const throw() { return (this->type == ZT_NETWORK_TYPE_PRIVATE); } + inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); } /** * @return ZeroTier addresses of devices on this network designated as active bridges @@ -361,7 +361,7 @@ public: /** * @return True if this network config is non-NULL */ - inline operator bool() const throw() { return (networkId != 0); } + inline operator bool() const { return (networkId != 0); } inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); } inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); } diff --git a/node/Node.cpp b/node/Node.cpp index dea0f5ca..f3339068 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -64,7 +64,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 _lastHousekeepingRun(0) { if (callbacks->version != 0) - throw std::runtime_error("callbacks struct version mismatch"); + throw ZT_EXCEPTION_INVALID_ARGUMENT; memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); // Initialize non-cryptographic PRNG from a good random source diff --git a/node/Node.hpp b/node/Node.hpp index e60da1ad..9658174f 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -114,7 +114,7 @@ public: // Internal functions ------------------------------------------------------ - inline uint64_t now() const throw() { return _now; } + inline uint64_t now() const { return _now; } inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { @@ -182,7 +182,7 @@ public: inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,tPtr,nwid,nuptr,op,nc); } - inline bool online() const throw() { return _online; } + inline bool online() const { return _online; } inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,maxlen); } inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,(int)len); } diff --git a/node/NonCopyable.hpp b/node/NonCopyable.hpp index 25c71b1c..5e8c753d 100644 --- a/node/NonCopyable.hpp +++ b/node/NonCopyable.hpp @@ -35,7 +35,7 @@ namespace ZeroTier { class NonCopyable { protected: - NonCopyable() throw() {} + NonCopyable() {} private: NonCopyable(const NonCopyable&); const NonCopyable& operator=(const NonCopyable&); diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 0c988804..486b66ff 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -90,18 +90,18 @@ public: /** * @return Multicast creation time */ - inline uint64_t timestamp() const throw() { return _timestamp; } + inline uint64_t timestamp() const { return _timestamp; } /** * @param now Current time * @return True if this multicast is expired (has exceeded transmit timeout) */ - inline bool expired(uint64_t now) const throw() { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } + inline bool expired(uint64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } /** * @return True if this outbound multicast has been sent to enough peers */ - inline bool atLimit() const throw() { return (_alreadySentTo.size() >= _limit); } + inline bool atLimit() const { return (_alreadySentTo.size() >= _limit); } /** * Just send without checking log diff --git a/node/Packet.hpp b/node/Packet.hpp index 4192b4e3..97c9774e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -424,8 +424,7 @@ public: } template - Fragment(const Buffer &b) - throw(std::out_of_range) : + Fragment(const Buffer &b) : Buffer(b) { } @@ -443,10 +442,8 @@ public: * @param fragLen Length of fragment in bytes * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) * @param fragTotal Total number of fragments (including 0) - * @throws std::out_of_range Packet size would exceed buffer */ Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - throw(std::out_of_range) { init(p,fragStart,fragLen,fragNo,fragTotal); } @@ -459,13 +456,11 @@ public: * @param fragLen Length of fragment in bytes * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) * @param fragTotal Total number of fragments (including 0) - * @throws std::out_of_range Packet size would exceed buffer */ inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - throw(std::out_of_range) { if ((fragStart + fragLen) > p.size()) - throw std::out_of_range("Packet::Fragment: tried to construct fragment of packet past its length"); + throw ZT_EXCEPTION_OUT_OF_BOUNDS; setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); // NOTE: this copies both the IV/packet ID and the destination address. diff --git a/node/Peer.cpp b/node/Peer.cpp index d362be9f..986e52ef 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -61,7 +61,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _credentialsCutoffCount(0) { if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) - throw std::runtime_error("new peer identity key agreement failed"); + throw ZT_EXCEPTION_INVALID_ARGUMENT; } void Peer::received( diff --git a/node/Peer.hpp b/node/Peer.hpp index 6d00e3e6..c6423a59 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -81,12 +81,12 @@ public: /** * @return This peer's ZT address (short for identity().address()) */ - inline const Address &address() const throw() { return _id.address(); } + inline const Address &address() const { return _id.address(); } /** * @return This peer's identity */ - inline const Identity &identity() const throw() { return _id; } + inline const Identity &identity() const { return _id; } /** * Log receipt of an authenticated packet diff --git a/node/Poly1305.cpp b/node/Poly1305.cpp index 46a51390..eceb57b3 100644 --- a/node/Poly1305.cpp +++ b/node/Poly1305.cpp @@ -121,7 +121,6 @@ static inline int crypto_onetimeauth(unsigned char *out,const unsigned char *in, } void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key) - throw() { crypto_onetimeauth((unsigned char *)auth,(const unsigned char *)data,len,(const unsigned char *)key); } @@ -623,7 +622,6 @@ poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { } // anonymous namespace void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key) - throw() { poly1305_context ctx; poly1305_init(&ctx,reinterpret_cast(key)); diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index ff709983..0bdfa74f 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -54,8 +54,7 @@ public: * @param len Length of data to authenticate in bytes * @param key 32-byte one-time use key to authenticate data (must not be reused) */ - static void compute(void *auth,const void *data,unsigned int len,const void *key) - throw(); + static void compute(void *auth,const void *data,unsigned int len,const void *key); }; } // namespace ZeroTier diff --git a/node/Revocation.hpp b/node/Revocation.hpp index e8f5d00d..a28da0ab 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -168,14 +168,14 @@ public: p += 2; memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; - } else throw std::runtime_error("invalid signature"); + } else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; } else { p += 2 + b.template at(p); } p += 2 + b.template at(p); if (p > b.size()) - throw std::runtime_error("extended field overflow"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; return (p - startAt); } diff --git a/node/Switch.hpp b/node/Switch.hpp index cebe9e67..346aaca3 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -222,8 +222,8 @@ private: y = a2.toInt(); } } - inline unsigned long hashCode() const throw() { return ((unsigned long)x ^ (unsigned long)y); } - inline bool operator==(const _LastUniteKey &k) const throw() { return ((x == k.x)&&(y == k.y)); } + inline unsigned long hashCode() const { return ((unsigned long)x ^ (unsigned long)y); } + inline bool operator==(const _LastUniteKey &k) const { return ((x == k.x)&&(y == k.y)); } uint64_t x,y; }; Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior diff --git a/node/Tag.hpp b/node/Tag.hpp index 746ade26..5fbfb278 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -161,7 +161,7 @@ public: _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; if (b[p++] == 1) { if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) - throw std::runtime_error("invalid signature length"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; p += 2; memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; } else { @@ -170,7 +170,7 @@ public: p += 2 + b.template at(p); if (p > b.size()) - throw std::runtime_error("extended field overflow"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; return (p - startAt); } diff --git a/node/World.hpp b/node/World.hpp index 003d70e3..71ab6e7c 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -110,9 +110,9 @@ public: Identity identity; std::vector stableEndpoints; - inline bool operator==(const Root &r) const throw() { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); } - inline bool operator!=(const Root &r) const throw() { return (!(*this == r)); } - inline bool operator<(const Root &r) const throw() { return (identity < r.identity); } // for sorting + inline bool operator==(const Root &r) const { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); } + inline bool operator!=(const Root &r) const { return (!(*this == r)); } + inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting }; /** @@ -212,7 +212,7 @@ public: case TYPE_PLANET: _type = TYPE_PLANET; break; case TYPE_MOON: _type = TYPE_MOON; break; default: - throw std::invalid_argument("invalid world type"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; } _id = b.template at(p); p += 8; @@ -221,14 +221,14 @@ public: memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN; const unsigned int numRoots = (unsigned int)b[p++]; if (numRoots > ZT_WORLD_MAX_ROOTS) - throw std::invalid_argument("too many roots in World"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; for(unsigned int k=0;k ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) - throw std::invalid_argument("too many stable endpoints in World/Root"); + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; for(unsigned int kk=0;kk Date: Wed, 23 Aug 2017 13:40:51 -0700 Subject: Implement peer serialization and deserialization. --- node/Peer.cpp | 2 +- node/Peer.hpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ node/Topology.cpp | 31 +++++++++++++++---- node/Topology.hpp | 2 ++ service/OneService.cpp | 25 ++++++++++++--- 5 files changed, 132 insertions(+), 12 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index 986e52ef..127f222c 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -369,7 +369,7 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) - attemptToContactAt(tPtr,InetAddress(),mp,now,true,0); + attemptToContactAt(tPtr,-1,mp,now,true,0); } } diff --git a/node/Peer.hpp b/node/Peer.hpp index c6423a59..af9163a5 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -439,6 +439,90 @@ public: return false; } + /** + * Serialize a peer for storage in local cache + * + * This does not serialize everything, just identity and addresses where the peer + * may be reached. + */ + template + inline void serialize(Buffer &b) const + { + b.append((uint8_t)0); + + _id.serialize(b); + + b.append(_lastReceive); + b.append(_lastNontrivialReceive); + b.append(_lastTriedMemorizedPath); + b.append(_lastDirectPathPushSent); + b.append(_lastDirectPathPushReceive); + b.append(_lastCredentialRequestSent); + b.append(_lastWhoisRequestReceived); + b.append(_lastEchoRequestReceived); + b.append(_lastComRequestReceived); + b.append(_lastComRequestSent); + b.append(_lastCredentialsReceived); + b.append(_lastTrustEstablishedPacketReceived); + + b.append((uint16_t)_vProto); + b.append((uint16_t)_vMajor); + b.append((uint16_t)_vMinor); + b.append((uint16_t)_vRevision); + + { + Mutex::Lock _l(_paths_m); + unsigned int pcount = 0; + if (_v4Path.p) ++pcount; + if (_v6Path.p) ++pcount; + b.append((uint8_t)pcount); + if (_v4Path.p) _v4Path.p->address().serialize(b); + if (_v6Path.p) _v6Path.p->address().serialize(b); + } + + b.append((uint16_t)0); + } + + template + inline static SharedPtr deserializeFromCache(uint64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) + { + try { + unsigned int ptr = 0; + if (b[ptr++] != 0) + return SharedPtr(); + + Identity id; + ptr += id.deserialize(b,ptr); + if (!id) + return SharedPtr(); + + SharedPtr p(new Peer(renv,renv->identity,id)); + + ptr += 12 * 8; // skip deserializing ephemeral state in this case + + p->_vProto = b.template at(ptr); ptr += 2; + p->_vMajor = b.template at(ptr); ptr += 2; + p->_vMinor = b.template at(ptr); ptr += 2; + p->_vRevision = b.template at(ptr); ptr += 2; + + const unsigned int pcount = (unsigned int)b[ptr++]; + for(unsigned int i=0;iattemptToContactAt(tPtr,-1,inaddr,now,true,0); + } catch ( ... ) { + break; + } + } + + return p; + } catch ( ... ) { + return SharedPtr(); + } + } + private: struct _PeerPath { diff --git a/node/Topology.cpp b/node/Topology.cpp index edca0180..aeca59a7 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -88,6 +88,15 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : addWorld(tPtr,defaultPlanet,false); } +Topology::~Topology() +{ + Hashtable< Address,SharedPtr >::Iterator i(_peers); + Address *a = (Address *)0; + SharedPtr *p = (SharedPtr *)0; + while (i.next(a,p)) + _savePeer((void *)0,*p); +} + SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { SharedPtr np; @@ -113,23 +122,21 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return *ap; } - /* try { - char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; + Buffer buf; uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; - int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf)); + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE); if (len > 0) { Mutex::Lock _l(_peers_m); SharedPtr &ap = _peers[zta]; if (ap) return ap; - ap = Peer::createFromStateUpdate(RR,tPtr,buf,len); + ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); if (!ap) _peers.erase(zta); return ap; } } catch ( ... ) {} // ignore invalid identities or other strage failures - */ return SharedPtr(); } @@ -383,8 +390,10 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { + _savePeer(tPtr,*p); _peers.erase(*a); + } } } @@ -440,4 +449,14 @@ void Topology::_memoizeUpstreams(void *tPtr) _cor.sign(RR->identity,RR->node->now()); } +void Topology::_savePeer(void *tPtr,const SharedPtr &peer) +{ + try { + Buffer buf; + peer->serialize(buf); + uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); + } catch ( ... ) {} // sanity check, discard invalid entries +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 30e58abc..04dfb1cc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -59,6 +59,7 @@ class Topology { public: Topology(const RuntimeEnvironment *renv,void *tPtr); + ~Topology(); /** * Add a peer to database @@ -419,6 +420,7 @@ public: private: Identity _getIdentity(void *tPtr,const Address &zta); void _memoizeUpstreams(void *tPtr); + void _savePeer(void *tPtr,const SharedPtr &peer); const RuntimeEnvironment *const RR; diff --git a/service/OneService.cpp b/service/OneService.cpp index f5f8700a..cd33e399 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2047,6 +2047,8 @@ public: char p[1024]; FILE *f; bool secure = false; + char dirname[1024]; + dirname[0] = 0; switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: @@ -2060,12 +2062,18 @@ public: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); secure = true; break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); + break; default: return; } @@ -2084,6 +2092,10 @@ public: } f = fopen(p,"w"); + if ((!f)&&(dirname[0])) { // create subdirectory if it does not exist + OSUtils::mkdir(dirname); + f = fopen(p,"w"); + } if (f) { if (fwrite(data,len,1,f) != 1) fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); @@ -2108,15 +2120,18 @@ public: case ZT_STATE_OBJECT_IDENTITY_SECRET: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); - break; case ZT_STATE_OBJECT_PLANET: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id); break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d/%.10llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + break; default: return -1; } -- cgit v1.2.3 From dd8b03a5c55baf7349ce075c8f4cad1d59cbe988 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 18:28:40 -0700 Subject: Threading issue fix? --- node/Peer.cpp | 7 +++++-- node/Switch.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index 127f222c..b3020854 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -424,18 +424,21 @@ void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remo SharedPtr op; SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + np->received(now); attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); { Mutex::Lock _l(_paths_m); if (remoteAddress.ss_family == AF_INET) { op = _v4Path.p; - _v4Path.p = np; + _v4Path.lr = now; _v4Path.sticky = now; + _v4Path.p = np; } else if (remoteAddress.ss_family == AF_INET6) { op = _v6Path.p; - _v6Path.p = np; + _v6Path.lr = now; _v6Path.sticky = now; + _v6Path.p = np; } } diff --git a/node/Switch.cpp b/node/Switch.cpp index fce12622..952bdef8 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -719,7 +719,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly + return false; } unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); -- cgit v1.2.3 From 52916eebcfae2559966d12d4be4b5376289a982d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 14 Sep 2017 20:56:50 -0700 Subject: Keep attemting to upgrade direct path if path is not private to facilitate better use of LANs and backplane networks. --- node/Peer.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Peer.cpp b/node/Peer.cpp index b3020854..a954b716 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -194,8 +194,12 @@ void Peer::received( } } } - } else if (this->trustEstablished(now)) { - // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) + } + + // If we are being relayed or if we're using a global address, send PUSH_DIRECT_PATHS. + // In the global address case we push only configured direct paths to accomplish + // fall-forward to local backplane networks over e.g. LAN or Amazon VPC. + if ( ((hops > 0)||(path->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) && (this->trustEstablished(now)) ) { if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; @@ -205,13 +209,15 @@ void Peer::received( for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) pathsToPush.push_back(*i); - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; + if (hops > 0) { + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } } } -- cgit v1.2.3 From b1d60df44cb24589bc5718da932ef4bb54168fa3 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Mon, 2 Oct 2017 15:52:57 -0700 Subject: timestamps changed from uint64_t to int64_t There were cases in the code where time calculations and comparisons were overflowing and causing connection instability. This will keep time calculations within expected ranges. --- controller/EmbeddedNetworkController.cpp | 14 +++--- controller/EmbeddedNetworkController.hpp | 8 ++-- controller/JSONDB.cpp | 4 +- controller/JSONDB.hpp | 2 +- include/ZeroTierOne.h | 12 ++--- node/CertificateOfMembership.hpp | 2 +- node/IncomingPacket.cpp | 12 ++--- node/IncomingPacket.hpp | 4 +- node/Membership.cpp | 8 ++-- node/Membership.hpp | 14 +++--- node/Multicaster.cpp | 8 ++-- node/Multicaster.hpp | 12 ++--- node/Network.cpp | 10 ++--- node/Network.hpp | 4 +- node/Node.cpp | 34 +++++++------- node/Node.hpp | 26 +++++------ node/OutboundMulticast.hpp | 2 +- node/Path.cpp | 2 +- node/Path.hpp | 22 ++++----- node/Peer.cpp | 35 ++++++++------- node/Peer.hpp | 76 ++++++++++++++++---------------- node/Revocation.hpp | 4 +- node/SelfAwareness.cpp | 6 +-- node/SelfAwareness.hpp | 4 +- node/Switch.cpp | 20 ++++----- node/Switch.hpp | 14 +++--- node/Topology.cpp | 7 +-- node/Topology.hpp | 4 +- one.cpp | 6 +-- osdep/OSUtils.hpp | 6 +-- osdep/PortMapper.cpp | 2 +- service/OneService.cpp | 22 +++++---- service/SoftwareUpdater.cpp | 2 +- service/SoftwareUpdater.hpp | 2 +- 34 files changed, 209 insertions(+), 201 deletions(-) (limited to 'node/Peer.cpp') diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 1d46d5e6..20f81966 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -535,7 +535,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( } else { // Get network - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); JSONDB::NetworkSummaryInfo ns; _db.getNetworkSummaryInfo(nwid,ns); _addNetworkNonPersistedFields(network,now,ns); @@ -602,7 +602,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( responseContentType = "application/json"; return 400; } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (path[0] == "network") { @@ -1087,7 +1087,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) } } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); OSUtils::ztsnprintf(id,sizeof(id),"%.10llx-%.10llx-%.16llx-%.8lx",_signingId.address().toInt(),rt.origin,now,++idCounter); d["id"] = id; d["objtype"] = "trace"; @@ -1129,7 +1129,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) void EmbeddedNetworkController::onNetworkUpdate(const uint64_t networkId) { // Send an update to all members of the network that are online - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); Mutex::Lock _l(_memberStatus_m); for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData)) @@ -1150,7 +1150,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const uint64_t networkId,c void EmbeddedNetworkController::onNetworkMemberDeauthorize(const uint64_t networkId,const uint64_t memberId) { - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); Revocation rev((uint32_t)_node->prng(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM); rev.sign(_signingId); { @@ -1224,7 +1224,7 @@ void EmbeddedNetworkController::_request( if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (requestPacketId) { Mutex::Lock _l(_memberStatus_m); @@ -1360,7 +1360,7 @@ void EmbeddedNetworkController::_request( // If we made it this far, they are authorized. // ------------------------------------------------------------------------- - uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; if (now > ns.mostRecentDeauthTime) { // If we recently de-authorized a member, shrink credential TTL/max delta to // be below the threshold required to exclude it. Cap this to a min/max to diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 19469164..fce56065 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -166,7 +166,7 @@ private: } network["objtype"] = "network"; } - inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const JSONDB::NetworkSummaryInfo &ns) + inline void _addNetworkNonPersistedFields(nlohmann::json &network,int64_t now,const JSONDB::NetworkSummaryInfo &ns) { network["clock"] = now; network["authorizedMemberCount"] = ns.authorizedMemberCount; @@ -182,7 +182,7 @@ private: // legacy fields network.erase("lastModified"); } - inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,uint64_t now) + inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,int64_t now) { member["clock"] = now; Mutex::Lock _l(_memberStatus_m); @@ -197,7 +197,7 @@ private: member.erase("lastRequestMetaData"); } - const uint64_t _startTime; + const int64_t _startTime; volatile bool _running; BlockingQueue<_RQEntry *> _queue; @@ -230,7 +230,7 @@ private: Dictionary lastRequestMetaData; Identity identity; InetAddress physicalAddr; // last known physical address - inline bool online(const uint64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } + inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); } }; struct _MemberStatusHash { diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index f362acf3..67b13393 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -323,7 +323,7 @@ void JSONDB::threadMain() _networks_m.unlock(); } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); try { Mutex::Lock _l(_networks_m); for(std::vector::iterator ii(todo.begin());ii!=todo.end();++ii) { @@ -373,7 +373,7 @@ void JSONDB::threadMain() } catch ( ... ) {} } else { try { - ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,OSUtils::jsonInt(member["lastDeauthorizedTime"],0ULL)); + ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,(int64_t)OSUtils::jsonInt(member["lastDeauthorizedTime"],0LL)); } catch ( ... ) {} } ++ns.totalMemberCount; diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index 44f4d7f5..db909cb0 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -57,7 +57,7 @@ public: unsigned long authorizedMemberCount; unsigned long activeMemberCount; unsigned long totalMemberCount; - uint64_t mostRecentDeauthTime; + int64_t mostRecentDeauthTime; }; JSONDB(const std::string &basePath,EmbeddedNetworkController *parent); diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index cf6b21fd..8adbc4d1 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1587,7 +1587,7 @@ struct ZT_Node_Callbacks * @param now Current clock in milliseconds * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); +ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); /** * Delete a node and free all resources it consumes @@ -1615,12 +1615,12 @@ ZT_SDK_API void ZT_Node_delete(ZT_Node *node); ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); /** * Process a frame from a virtual network port (tap) @@ -1641,7 +1641,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -1649,7 +1649,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); /** * Perform periodic background operations @@ -1660,7 +1660,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); +ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); /** * Join a network diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 3ffa814f..0105fade 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -176,7 +176,7 @@ public: /** * @return Timestamp for this cert and maximum delta for timestamp */ - inline uint64_t timestamp() const + inline int64_t timestamp() const { for(unsigned int i=0;i<_qualifierCount;++i) { if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 685f2f09..c0409c91 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -169,7 +169,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar // Peers can send this in response to frames if they do not have a recent enough COM from us networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); const SharedPtr network(RR->node->network(networkId)); - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(tPtr,peer->address(),now); } break; @@ -202,7 +202,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); const uint64_t pid = packetId(); const Address fromAddress(source()); @@ -210,7 +210,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); - const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); + const int64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id; unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); @@ -725,7 +725,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); uint64_t authOnNetwork[256]; // cache for approved network IDs unsigned int authOnNetworkCount = 0; @@ -1082,7 +1082,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); // First, subject this to a rate limit if (!peer->rateGatePushDirectPaths(now)) { @@ -1186,7 +1186,7 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); if (peer->rateGateOutgoingComRequest(now)) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)verb()); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 45a0166d..c8f52721 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -77,7 +77,7 @@ public: * @param now Current time * @throws std::out_of_range Range error processing packet */ - IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) : + IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,int64_t now) : Packet(data,len), _receiveTime(now), _path(path) @@ -93,7 +93,7 @@ public: * @param now Current time * @throws std::out_of_range Range error processing packet */ - inline void init(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) + inline void init(const void *data,unsigned int len,const SharedPtr &path,int64_t now) { copyFrom(data,len); _receiveTime = now; diff --git a/node/Membership.cpp b/node/Membership.cpp index 17de6554..740f4e68 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -51,7 +51,7 @@ Membership::Membership() : resetPushState(); } -void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force) +void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force) { bool sendCom = ( (nconf.com) && ( ((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) ); @@ -127,13 +127,13 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const u Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) { - const uint64_t newts = com.timestamp(); + const int64_t newts = com.timestamp(); if (newts <= _comRevocationThreshold) { RR->t->credentialRejected(tPtr,com,"revoked"); return ADD_REJECTED; } - const uint64_t oldts = _com.timestamp(); + const int64_t oldts = _com.timestamp(); if (newts < oldts) { RR->t->credentialRejected(tPtr,com,"old"); return ADD_REJECTED; @@ -227,7 +227,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -void Membership::clean(const uint64_t now,const NetworkConfig &nconf) +void Membership::clean(const int64_t now,const NetworkConfig &nconf) { _cleanCredImpl(nconf,_remoteTags); _cleanCredImpl(nconf,_remoteCaps); diff --git a/node/Membership.hpp b/node/Membership.hpp index c6e2b803..5612858a 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -80,7 +80,7 @@ public: * @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none * @param force If true, send objects regardless of last push time */ - void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); + void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force); /** * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true @@ -88,7 +88,7 @@ public: * @param now Current time * @return True if we should update multicasts */ - inline bool multicastLikeGate(const uint64_t now) + inline bool multicastLikeGate(const int64_t now) { if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) { _lastUpdatedMulticast = now; @@ -110,7 +110,7 @@ public: return nconf.com.agreesWith(_com); } - inline bool recentlyAssociated(const uint64_t now) const + inline bool recentlyAssociated(const int64_t now) const { return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); } @@ -180,7 +180,7 @@ public: * @param now Current time * @param nconf Current network configuration */ - void clean(const uint64_t now,const NetworkConfig &nconf); + void clean(const int64_t now,const NetworkConfig &nconf); /** * Reset last pushed time for local credentials @@ -223,13 +223,13 @@ private: } // Last time we pushed MULTICAST_LIKE(s) - uint64_t _lastUpdatedMulticast; + int64_t _lastUpdatedMulticast; // Last time we pushed our COM to this peer - uint64_t _lastPushedCom; + int64_t _lastPushedCom; // Revocation threshold for COM or 0 if none - uint64_t _comRevocationThreshold; + int64_t _comRevocationThreshold; // Remote member's latest network COM CertificateOfMembership _com; diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index e8c8613a..fa6f7bd1 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -51,7 +51,7 @@ Multicaster::~Multicaster() { } -void Multicaster::addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) +void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) { const unsigned char *p = (const unsigned char *)addresses; const unsigned char *e = p + (5 * count); @@ -160,7 +160,7 @@ std::vector
Multicaster::getMembers(uint64_t nwid,const MulticastGroup void Multicaster::send( void *tPtr, unsigned int limit, - uint64_t now, + int64_t now, uint64_t nwid, bool disableCompression, const std::vector
&alwaysSendTo, @@ -309,7 +309,7 @@ void Multicaster::send( delete [] indexes; } -void Multicaster::clean(uint64_t now) +void Multicaster::clean(int64_t now) { { Mutex::Lock _l(_groups_m); @@ -367,7 +367,7 @@ void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bo } } -void Multicaster::_add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) +void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) { // assumes _groups_m is locked diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 69a6645d..08c96485 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -98,7 +98,7 @@ public: * @param mg Multicast group * @param member New member address */ - inline void add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) + inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) { Mutex::Lock _l(_groups_m); _add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); @@ -117,7 +117,7 @@ public: * @param count Number of addresses * @param totalKnown Total number of known addresses as reported by peer */ - void addMultiple(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); + void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); /** * Remove a multicast group member (if present) @@ -174,7 +174,7 @@ public: void send( void *tPtr, unsigned int limit, - uint64_t now, + int64_t now, uint64_t nwid, bool disableCompression, const std::vector
&alwaysSendTo, @@ -190,7 +190,7 @@ public: * @param RR Runtime environment * @param now Current time */ - void clean(uint64_t now); + void clean(int64_t now); /** * Add an authorization credential @@ -212,7 +212,7 @@ public: * @param now Current time * @return True if GATHER and LIKE should be allowed */ - bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const + bool cacheAuthorized(const Address &a,const uint64_t nwid,const int64_t now) const { Mutex::Lock _l(_gatherAuth_m); const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a)); @@ -220,7 +220,7 @@ public: } private: - void _add(void *tPtr,uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); + void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); const RuntimeEnvironment *RR; diff --git a/node/Network.cpp b/node/Network.cpp index 16155c33..111e4736 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -592,7 +592,7 @@ bool Network::filterOutgoingPacket( const unsigned int etherType, const unsigned int vlanId) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); Address ztFinalDest(ztDest); int localCapabilityIndex = -1; int accept = 0; @@ -1164,7 +1164,7 @@ void Network::requestConfiguration(void *tPtr) bool Network::gate(void *tPtr,const SharedPtr &peer) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); Mutex::Lock _l(_lock); try { if (_config) { @@ -1192,7 +1192,7 @@ bool Network::recentlyAssociatedWith(const Address &addr) void Network::clean() { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); Mutex::Lock _l(_lock); if (_destroyed) @@ -1257,7 +1257,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr) } } -void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now) +void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now) { Mutex::Lock _l(_lock); const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); @@ -1377,7 +1377,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) { // Assumes _lock is locked - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); std::vector groups; if (newMulticastGroup) diff --git a/node/Network.hpp b/node/Network.hpp index d4d217f2..1b4da7d2 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -305,7 +305,7 @@ public: * @param mg Multicast group * @param now Current time */ - void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,uint64_t now); + void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now); /** * Validate a credential and learn it if it passes certificate and other checks @@ -357,7 +357,7 @@ public: * @param to Destination peer address * @param now Current time */ - inline void pushCredentialsNow(void *tPtr,const Address &to,const uint64_t now) + inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now) { Mutex::Lock _l(_lock); _membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true); diff --git a/node/Node.cpp b/node/Node.cpp index cc076e4d..31ee8f19 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -54,7 +54,7 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) : +Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) : _RR(this), RR(&_RR), _uPtr(uptr), @@ -139,12 +139,12 @@ Node::~Node() ZT_ResultCode Node::processWirePacket( void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { _now = now; RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast(remoteAddress)),packetData,packetLength); @@ -153,7 +153,7 @@ ZT_ResultCode Node::processWirePacket( ZT_ResultCode Node::processVirtualNetworkFrame( void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -161,7 +161,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { _now = now; SharedPtr nw(this->network(nwid)); @@ -175,7 +175,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame( class _PingPeersThatNeedPing { public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,uint64_t now) : + _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &upstreamsToContact,int64_t now) : lastReceiveFromUpstream(0), RR(renv), _tPtr(tPtr), @@ -185,7 +185,7 @@ public: { } - uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay + int64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay inline void operator()(Topology &t,const SharedPtr &p) { @@ -234,17 +234,17 @@ private: const RuntimeEnvironment *RR; void *_tPtr; Hashtable< Address,std::vector > &_upstreamsToContact; - const uint64_t _now; + const int64_t _now; const SharedPtr _bestCurrentUpstream; }; -ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) { _now = now; Mutex::Lock bl(_backgroundTasksLock); unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL; - const uint64_t timeSinceLastPingCheck = now - _lastPingCheck; + const int64_t timeSinceLastPingCheck = now - _lastPingCheck; if (timeSinceLastPingCheck >= ZT_PING_CHECK_INVERVAL) { try { _lastPingCheck = now; @@ -305,7 +305,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } try { - *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); + *nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); } catch ( ... ) { return ZT_RESULT_FATAL_ERROR_INTERNAL; } @@ -689,7 +689,7 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now) +enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) { *node = (ZT_Node *)0; try { @@ -714,12 +714,12 @@ void ZT_Node_delete(ZT_Node *node) enum ZT_ResultCode ZT_Node_processWirePacket( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { try { return reinterpret_cast(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); @@ -733,7 +733,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_Node *node, void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -741,7 +741,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline) + volatile int64_t *nextBackgroundTaskDeadline) { try { return reinterpret_cast(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); @@ -752,7 +752,7 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( } } -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) { try { return reinterpret_cast(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline); diff --git a/node/Node.hpp b/node/Node.hpp index 1aa01c9a..ae7976d4 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -64,7 +64,7 @@ class World; class Node : public NetworkController::Sender { public: - Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint64_t now); + Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); virtual ~Node(); // Get rid of alignment warnings on 32-bit Windows and possibly improve performance @@ -77,15 +77,15 @@ public: ZT_ResultCode processWirePacket( void *tptr, - uint64_t now, + int64_t now, int64_t localSocket, const struct sockaddr_storage *remoteAddress, const void *packetData, unsigned int packetLength, - volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); ZT_ResultCode processVirtualNetworkFrame( void *tptr, - uint64_t now, + int64_t now, uint64_t nwid, uint64_t sourceMac, uint64_t destMac, @@ -93,8 +93,8 @@ public: unsigned int vlanId, const void *frameData, unsigned int frameLength, - volatile uint64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processBackgroundTasks(void *tptr,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline); + volatile int64_t *nextBackgroundTaskDeadline); + ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); @@ -114,7 +114,7 @@ public: // Internal functions ------------------------------------------------------ - inline uint64_t now() const { return _now; } + inline int64_t now() const { return _now; } inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) { @@ -243,7 +243,7 @@ public: * @param from Source address of packet * @return True if within rate limits */ - inline bool rateGateIdentityVerification(const uint64_t now,const InetAddress &from) + inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from) { unsigned long iph = from.rateGateHash(); if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { @@ -270,7 +270,7 @@ private: uint32_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; // Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification() - uint64_t _lastIdentityVerification[16384]; + int64_t _lastIdentityVerification[16384]; Hashtable< uint64_t,SharedPtr > _networks; Mutex _networks_m; @@ -281,10 +281,10 @@ private: Mutex _backgroundTasksLock; Address _remoteTraceTarget; - uint64_t _now; - uint64_t _lastPingCheck; - uint64_t _lastHousekeepingRun; - volatile uint64_t _prngState[2]; + int64_t _now; + int64_t _lastPingCheck; + int64_t _lastHousekeepingRun; + volatile int64_t _prngState[2]; bool _online; }; diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 486b66ff..2f6d8338 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -96,7 +96,7 @@ public: * @param now Current time * @return True if this multicast is expired (has exceeded transmit timeout) */ - inline bool expired(uint64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } + inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } /** * @return True if this outbound multicast has been sent to enough peers diff --git a/node/Path.cpp b/node/Path.cpp index 9dc9aba5..ca366e39 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -30,7 +30,7 @@ namespace ZeroTier { -bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now) +bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now) { if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { _lastOut = now; diff --git a/node/Path.hpp b/node/Path.hpp index ac8e4c0e..050fb6e2 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -179,14 +179,14 @@ public: * @param now Current time * @return True if transport reported success */ - bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,uint64_t now); + bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now); /** * Manually update last sent time * * @param t Time of send */ - inline void sent(const uint64_t t) { _lastOut = t; } + inline void sent(const int64_t t) { _lastOut = t; } /** * @return Local socket as specified by external code @@ -206,7 +206,7 @@ public: /** * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms */ - inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } /** * @return Preference rank, higher == better @@ -261,27 +261,27 @@ public: /** * @return True if path appears alive */ - inline bool alive(const uint64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } + inline bool alive(const int64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } /** * @return True if this path needs a heartbeat */ - inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } + inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } /** * @return Last time we sent something */ - inline uint64_t lastOut() const { return _lastOut; } + inline int64_t lastOut() const { return _lastOut; } /** * @return Last time we received anything */ - inline uint64_t lastIn() const { return _lastIn; } + inline int64_t lastIn() const { return _lastIn; } /** * @return Time last trust-established packet was received */ - inline uint64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } + inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } /** * Return and increment outgoing packet counter (used with Packet::armor()) @@ -291,9 +291,9 @@ public: inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } private: - volatile uint64_t _lastOut; - volatile uint64_t _lastIn; - volatile uint64_t _lastTrustEstablishedPacketReceived; + volatile int64_t _lastOut; + volatile int64_t _lastIn; + volatile int64_t _lastTrustEstablishedPacketReceived; volatile uint64_t _incomingLinkQualityFastLog; int64_t _localSocket; volatile unsigned long _incomingLinkQualitySlowLogPtr; diff --git a/node/Peer.cpp b/node/Peer.cpp index a954b716..60661592 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -34,6 +34,7 @@ #include "SelfAwareness.hpp" #include "Packet.hpp" #include "Trace.hpp" +#include "InetAddress.hpp" namespace ZeroTier { @@ -75,7 +76,7 @@ void Peer::received( const bool trustEstablished, const uint64_t networkId) { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); /* #ifdef ZT_ENABLE_CLUSTER @@ -263,14 +264,14 @@ void Peer::received( } } -bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force) +bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force) { Mutex::Lock _l(_paths_m); - uint64_t v6lr = 0; + int64_t v6lr = 0; if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) v6lr = _v6Path.p->lastIn(); - uint64_t v4lr = 0; + int64_t v4lr = 0; if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) v4lr = _v4Path.p->lastIn(); @@ -289,16 +290,18 @@ bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now, return false; } -SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) +SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) { Mutex::Lock _l(_paths_m); - uint64_t v6lr = 0; - if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) ) + int64_t v6lr = 0; + if ((includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v6Path.p)) { v6lr = _v6Path.p->lastIn(); - uint64_t v4lr = 0; - if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) ) + } + int64_t v4lr = 0; + if ((includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v4Path.p)) { v4lr = _v4Path.p->lastIn(); + } if (v6lr > v4lr) { return _v6Path.p; @@ -309,7 +312,7 @@ SharedPtr Peer::getBestPath(uint64_t now,bool includeExpired) return SharedPtr(); } -void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -357,7 +360,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA } } -void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); @@ -369,7 +372,7 @@ void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAdd } } -void Peer::tryMemorizedPath(void *tPtr,uint64_t now) +void Peer::tryMemorizedPath(void *tPtr,int64_t now) { if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { _lastTriedMemorizedPath = now; @@ -379,15 +382,15 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now) } } -bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) +bool Peer::doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily) { Mutex::Lock _l(_paths_m); if (inetAddressFamily < 0) { - uint64_t v6lr = 0; + int64_t v6lr = 0; if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) v6lr = _v6Path.p->lastIn(); - uint64_t v4lr = 0; + int64_t v4lr = 0; if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) v4lr = _v4Path.p->lastIn(); @@ -423,7 +426,7 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily) return false; } -void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now) +void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) { if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check return; diff --git a/node/Peer.hpp b/node/Peer.hpp index af9163a5..e08f7d36 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -120,7 +120,7 @@ public: * @param addr Remote address * @return True if we have an active path to this destination */ - inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const + inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); @@ -136,7 +136,7 @@ public: * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force); + bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force); /** * Get the best current direct path @@ -148,7 +148,7 @@ public: * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none */ - SharedPtr getBestPath(uint64_t now,bool includeExpired); + SharedPtr getBestPath(int64_t now,bool includeExpired); /** * Send a HELLO to this peer at a specified physical address @@ -161,7 +161,7 @@ public: * @param now Current time * @param counter Outgoing packet counter */ - void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -175,7 +175,7 @@ public: * @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param counter Outgoing packet counter */ - void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter); /** * Try a memorized or statically defined path if any are known @@ -185,7 +185,7 @@ public: * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time */ - void tryMemorizedPath(void *tPtr,uint64_t now); + void tryMemorizedPath(void *tPtr,int64_t now); /** * Send pings or keepalives depending on configured timeouts @@ -195,7 +195,7 @@ public: * @param inetAddressFamily Keep this address family alive, or -1 for any * @return True if we have at least one direct path of the given family (or any if family is -1) */ - bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily); + bool doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily); /** * Specify remote path for this peer and forget others @@ -209,7 +209,7 @@ public: * @param remoteAddress Remote address * @param now Current time */ - void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const uint64_t now); + void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); /** * Reset paths within a given IP scope and address family @@ -222,7 +222,7 @@ public: * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now) + inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) { Mutex::Lock _l(_paths_m); if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { @@ -243,7 +243,7 @@ public: * @param v4 Result parameter to receive active IPv4 address, if any * @param v6 Result parameter to receive active IPv6 address, if any */ - inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const + inline void getRendezvousAddresses(int64_t now,InetAddress &v4,InetAddress &v6) const { Mutex::Lock _l(_paths_m); if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) @@ -256,7 +256,7 @@ public: * @param now Current time * @return All known paths to this peer */ - inline std::vector< SharedPtr > paths(const uint64_t now) const + inline std::vector< SharedPtr > paths(const int64_t now) const { std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); @@ -270,17 +270,17 @@ public: /** * @return Time of last receive of anything, whether direct or relayed */ - inline uint64_t lastReceive() const { return _lastReceive; } + inline int64_t lastReceive() const { return _lastReceive; } /** * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT */ - inline bool isAlive(const uint64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return True if this peer has sent us real network traffic recently */ - inline uint64_t isActive(uint64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } /** * @return Latency in milliseconds or 0 if unknown @@ -298,7 +298,7 @@ public: * * @return Relay quality score computed from latency and other factors, lower is better */ - inline unsigned int relayQuality(const uint64_t now) const + inline unsigned int relayQuality(const int64_t now) const { const uint64_t tsr = now - _lastReceive; if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) @@ -353,12 +353,12 @@ public: /** * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms */ - inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } /** * Rate limit gate for VERB_PUSH_DIRECT_PATHS */ - inline bool rateGatePushDirectPaths(const uint64_t now) + inline bool rateGatePushDirectPaths(const int64_t now) { if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) ++_directPathPushCutoffCount; @@ -370,7 +370,7 @@ public: /** * Rate limit gate for VERB_NETWORK_CREDENTIALS */ - inline bool rateGateCredentialsReceived(const uint64_t now) + inline bool rateGateCredentialsReceived(const int64_t now) { if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME) ++_credentialsCutoffCount; @@ -382,7 +382,7 @@ public: /** * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE */ - inline bool rateGateRequestCredentials(const uint64_t now) + inline bool rateGateRequestCredentials(const int64_t now) { if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastCredentialRequestSent = now; @@ -394,7 +394,7 @@ public: /** * Rate limit gate for inbound WHOIS requests */ - inline bool rateGateInboundWhoisRequest(const uint64_t now) + inline bool rateGateInboundWhoisRequest(const int64_t now) { if ((now - _lastWhoisRequestReceived) >= ZT_PEER_WHOIS_RATE_LIMIT) { _lastWhoisRequestReceived = now; @@ -406,7 +406,7 @@ public: /** * Rate limit gate for inbound ECHO requests */ - inline bool rateGateEchoRequest(const uint64_t now) + inline bool rateGateEchoRequest(const int64_t now) { if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastEchoRequestReceived = now; @@ -418,7 +418,7 @@ public: /** * Rate gate incoming requests for network COM */ - inline bool rateGateIncomingComRequest(const uint64_t now) + inline bool rateGateIncomingComRequest(const int64_t now) { if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestReceived = now; @@ -430,7 +430,7 @@ public: /** * Rate gate outgoing requests for network COM */ - inline bool rateGateOutgoingComRequest(const uint64_t now) + inline bool rateGateOutgoingComRequest(const int64_t now) { if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestSent = now; @@ -484,7 +484,7 @@ public: } template - inline static SharedPtr deserializeFromCache(uint64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) + inline static SharedPtr deserializeFromCache(int64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) { try { unsigned int ptr = 0; @@ -527,8 +527,8 @@ private: struct _PeerPath { _PeerPath() : lr(0),sticky(0),p() {} - uint64_t lr; // time of last valid ZeroTier packet - uint64_t sticky; // time last set as sticky + int64_t lr; // time of last valid ZeroTier packet + int64_t sticky; // time last set as sticky SharedPtr p; }; @@ -536,18 +536,18 @@ private: const RuntimeEnvironment *RR; - uint64_t _lastReceive; // direct or indirect - uint64_t _lastNontrivialReceive; // frames, things like netconf, etc. - uint64_t _lastTriedMemorizedPath; - uint64_t _lastDirectPathPushSent; - uint64_t _lastDirectPathPushReceive; - uint64_t _lastCredentialRequestSent; - uint64_t _lastWhoisRequestReceived; - uint64_t _lastEchoRequestReceived; - uint64_t _lastComRequestReceived; - uint64_t _lastComRequestSent; - uint64_t _lastCredentialsReceived; - uint64_t _lastTrustEstablishedPacketReceived; + int64_t _lastReceive; // direct or indirect + int64_t _lastNontrivialReceive; // frames, things like netconf, etc. + int64_t _lastTriedMemorizedPath; + int64_t _lastDirectPathPushSent; + int64_t _lastDirectPathPushReceive; + int64_t _lastCredentialRequestSent; + int64_t _lastWhoisRequestReceived; + int64_t _lastEchoRequestReceived; + int64_t _lastComRequestReceived; + int64_t _lastComRequestSent; + int64_t _lastCredentialsReceived; + int64_t _lastTrustEstablishedPacketReceived; uint16_t _vProto; uint16_t _vMajor; diff --git a/node/Revocation.hpp b/node/Revocation.hpp index a28da0ab..7f7498bb 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -85,7 +85,7 @@ public: inline uint32_t id() const { return _id; } inline uint32_t credentialId() const { return _credentialId; } inline uint64_t networkId() const { return _networkId; } - inline uint64_t threshold() const { return _threshold; } + inline int64_t threshold() const { return _threshold; } inline const Address &target() const { return _target; } inline const Address &signer() const { return _signedBy; } inline Credential::Type type() const { return _type; } @@ -184,7 +184,7 @@ private: uint32_t _id; uint32_t _credentialId; uint64_t _networkId; - uint64_t _threshold; + int64_t _threshold; uint64_t _flags; Address _target; Address _signedBy; diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 0af0d691..83cd89c9 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -49,7 +49,7 @@ namespace ZeroTier { class _ResetWithinScope { public: - _ResetWithinScope(void *tPtr,uint64_t now,int inetAddressFamily,InetAddress::IpScope scope) : + _ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), @@ -70,7 +70,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now) +void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -112,7 +112,7 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive } } -void SelfAwareness::clean(uint64_t now) +void SelfAwareness::clean(int64_t now) { Mutex::Lock _l(_phy_m); Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 35e0ad39..7ddba465 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -55,14 +55,14 @@ public: * @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param now Current time */ - void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now); + void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now); /** * Clean up database periodically * * @param now Current time */ - void clean(uint64_t now); + void clean(int64_t now); /** * If we appear to be behind a symmetric NAT, get predictions for possible external endpoints diff --git a/node/Switch.cpp b/node/Switch.cpp index f46b3e73..cc022b6b 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -57,7 +57,7 @@ Switch::Switch(const RuntimeEnvironment *renv) : void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len) { try { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); const SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); @@ -557,14 +557,14 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) } } -void Switch::requestWhois(void *tPtr,const uint64_t now,const Address &addr) +void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr) { if (addr == RR->identity.address()) return; { Mutex::Lock _l(_lastSentWhoisRequest_m); - uint64_t &last = _lastSentWhoisRequest[addr]; + int64_t &last = _lastSentWhoisRequest[addr]; if ((now - last) < ZT_WHOIS_RETRY_DELAY) return; else last = now; @@ -586,7 +586,7 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) _lastSentWhoisRequest.erase(peer->address()); } - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); for(unsigned int ptr=0;ptrtimestamp)&&(rq->complete)) { @@ -611,7 +611,7 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) } } -unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) +unsigned long Switch::doTimerTasks(void *tPtr,int64_t now) { const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) @@ -663,9 +663,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) { Mutex::Lock _l(_lastSentWhoisRequest_m); - Hashtable< Address,uint64_t >::Iterator i(_lastSentWhoisRequest); + Hashtable< Address,int64_t >::Iterator i(_lastSentWhoisRequest); Address *a = (Address *)0; - uint64_t *ts = (uint64_t *)0; + int64_t *ts = (int64_t *)0; while (i.next(a,ts)) { if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) _lastSentWhoisRequest.erase(*a); @@ -675,7 +675,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) return ZT_WHOIS_RETRY_DELAY; } -bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination) +bool Switch::_shouldUnite(const int64_t now,const Address &source,const Address &destination) { Mutex::Lock _l(_lastUniteAttempt_m); uint64_t &ts = _lastUniteAttempt[_LastUniteKey(source,destination)]; @@ -689,7 +689,7 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); const Address destination(packet.destination()); const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); @@ -703,7 +703,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) viaPath = peer->getBestPath(now,false); if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { + if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(int64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); viaPath->sent(now); } diff --git a/node/Switch.hpp b/node/Switch.hpp index c258a255..b42389fc 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -114,7 +114,7 @@ public: * @param now Current time * @param addr Address to look up */ - void requestWhois(void *tPtr,const uint64_t now,const Address &addr); + void requestWhois(void *tPtr,const int64_t now,const Address &addr); /** * Run any processes that are waiting for this peer's identity @@ -136,25 +136,25 @@ public: * @param now Current time * @return Number of milliseconds until doTimerTasks() should be run again */ - unsigned long doTimerTasks(void *tPtr,uint64_t now); + unsigned long doTimerTasks(void *tPtr,int64_t now); private: - bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); + bool _shouldUnite(const int64_t now,const Address &source,const Address &destination); bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; - uint64_t _lastBeaconResponse; - volatile uint64_t _lastCheckedQueues; + int64_t _lastBeaconResponse; + volatile int64_t _lastCheckedQueues; // Time we last sent a WHOIS request for each address - Hashtable< Address,uint64_t > _lastSentWhoisRequest; + Hashtable< Address,int64_t > _lastSentWhoisRequest; Mutex _lastSentWhoisRequest_m; // Packets waiting for WHOIS replies or other decode info or missing fragments struct RXQueueEntry { RXQueueEntry() : timestamp(0) {} - volatile uint64_t timestamp; // 0 if entry is not in use + volatile int64_t timestamp; // 0 if entry is not in use volatile uint64_t packetId; IncomingPacket frag0; // head of packet Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) diff --git a/node/Topology.cpp b/node/Topology.cpp index 8a830b93..f884e9c3 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -133,8 +133,9 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) if (ap) return ap; ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); - if (!ap) + if (!ap) { _peers.erase(zta); + } return SharedPtr(); } } catch ( ... ) {} // ignore invalid identities or other strage failures @@ -157,7 +158,7 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) SharedPtr Topology::getUpstreamPeer() { - const uint64_t now = RR->node->now(); + const int64_t now = RR->node->now(); unsigned int bestq = ~((unsigned int)0); const SharedPtr *best = (const SharedPtr *)0; @@ -365,7 +366,7 @@ void Topology::removeMoon(void *tPtr,const uint64_t id) _memoizeUpstreams(tPtr); } -void Topology::doPeriodicTasks(void *tPtr,uint64_t now) +void Topology::doPeriodicTasks(void *tPtr,int64_t now) { { Mutex::Lock _l1(_peers_m); diff --git a/node/Topology.hpp b/node/Topology.hpp index 34df28a1..c3a218e3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -286,13 +286,13 @@ public: /** * Clean and flush database */ - void doPeriodicTasks(void *tPtr,uint64_t now); + void doPeriodicTasks(void *tPtr,int64_t now); /** * @param now Current time * @return Number of peers with active direct paths */ - inline unsigned long countActive(uint64_t now) const + inline unsigned long countActive(int64_t now) const { unsigned long cnt = 0; Mutex::Lock _l(_peers_m); diff --git a/one.cpp b/one.cpp index b1a19e8c..de16cc2d 100644 --- a/one.cpp +++ b/one.cpp @@ -364,9 +364,9 @@ static int cli(int argc,char **argv) if (path["preferred"]) { char tmp[256]; std::string addr = path["address"]; - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); const double lq = (path.count("linkQuality")) ? (double)path["linkQuality"] : -1.0; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%llu;%llu;%1.2f",addr.c_str(),now - (uint64_t)path["lastSend"],now - (uint64_t)path["lastReceive"],lq); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld;%1.2f",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"],lq); bestPath = tmp; break; } @@ -864,7 +864,7 @@ static int idtool(int argc,char **argv) } std::sort(roots.begin(),roots.end()); - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey)); Buffer wbuf; w.serialize(wbuf); diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 8683ba25..8f66f850 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -200,7 +200,7 @@ public: /** * @return Current time in milliseconds since epoch */ - static inline uint64_t now() + static inline int64_t now() { #ifdef __WINDOWS__ FILETIME ft; @@ -210,7 +210,7 @@ public: SystemTimeToFileTime(&st,&ft); tmp.LowPart = ft.dwLowDateTime; tmp.HighPart = ft.dwHighDateTime; - return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds ); + return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds ); #else struct timeval tv; #ifdef __LINUX__ @@ -218,7 +218,7 @@ public: #else gettimeofday(&tv,(struct timezone *)0); #endif - return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) ); + return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) ); #endif }; diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index 0da00653..825972b0 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -131,7 +131,7 @@ public: InetAddress publicAddress; sendpublicaddressrequest(&natpmp); - uint64_t myTimeout = OSUtils::now() + 5000; + int64_t myTimeout = OSUtils::now() + 5000; do { fd_set fds; struct timeval timeout; diff --git a/service/OneService.cpp b/service/OneService.cpp index 66e9a9c8..fb185ee7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -276,6 +276,10 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) pa.push_back(j); } pj["paths"] = pa; + + if (peer->address == 0xda6c71a1ad) { + fprintf(stdout, "%s\n", pj.dump(2).c_str()); + } } static void _moonToJson(nlohmann::json &mj,const World &world) @@ -436,7 +440,7 @@ public: uint64_t _lastRestart; // Deadline for the next background task service function - volatile uint64_t _nextBackgroundTaskDeadline; + volatile int64_t _nextBackgroundTaskDeadline; // Configured networks struct NetworkState @@ -755,12 +759,12 @@ public: // Main I/O loop _nextBackgroundTaskDeadline = 0; - uint64_t clockShouldBe = OSUtils::now(); + int64_t clockShouldBe = OSUtils::now(); _lastRestart = clockShouldBe; - uint64_t lastTapMulticastGroupCheck = 0; - uint64_t lastBindRefresh = 0; - uint64_t lastUpdateCheck = clockShouldBe; - uint64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle + int64_t lastTapMulticastGroupCheck = 0; + int64_t lastBindRefresh = 0; + int64_t lastUpdateCheck = clockShouldBe; + int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle for(;;) { _run_m.lock(); if (!_run) { @@ -773,7 +777,7 @@ public: _run_m.unlock(); } - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); // Attempt to detect sleep/wake events by detecting delay overruns bool restarted = false; @@ -809,7 +813,7 @@ public: } // Run background task processor in core if it's time to do so - uint64_t dl = _nextBackgroundTaskDeadline; + int64_t dl = _nextBackgroundTaskDeadline; if (dl <= now) { _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); dl = _nextBackgroundTaskDeadline; @@ -2152,7 +2156,7 @@ public: // Engage TCP tunnel fallback if we haven't received anything valid from a global // IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting // valid direct traffic we'll stop using it and close the socket after a while. - const uint64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { if (_tcpFallbackTunnel) { bool flushNow = false; diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 11005945..39833c90 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -303,7 +303,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void } } -bool SoftwareUpdater::check(const uint64_t now) +bool SoftwareUpdater::check(const int64_t now) { if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) { _lastCheckTime = now; diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index ff3e36df..f16c99a0 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -167,7 +167,7 @@ public: * * @return True if we've downloaded and verified an update */ - bool check(const uint64_t now); + bool check(const int64_t now); /** * @return Meta-data for downloaded update or NULL if none -- cgit v1.2.3 From c7d370c17fc8b44f4d83868de9c6958347b75ca2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 24 Oct 2017 14:49:38 -0700 Subject: Delete something that turns out not to be useful. This will be handled differently. --- node/CertificateOfRepresentation.hpp | 188 ----------------------------------- node/Credential.hpp | 1 - node/IncomingPacket.cpp | 24 ----- node/Peer.cpp | 5 - node/Topology.cpp | 7 -- node/Topology.hpp | 21 ---- node/Trace.cpp | 13 --- node/Trace.hpp | 2 - 8 files changed, 261 deletions(-) delete mode 100644 node/CertificateOfRepresentation.hpp (limited to 'node/Peer.cpp') diff --git a/node/CertificateOfRepresentation.hpp b/node/CertificateOfRepresentation.hpp deleted file mode 100644 index 3007f1dc..00000000 --- a/node/CertificateOfRepresentation.hpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 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 . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. - */ - -#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP -#define ZT_CERTIFICATEOFREPRESENTATION_HPP - -#include "Constants.hpp" -#include "Credential.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" - -/** - * Maximum number of addresses allowed in a COR - */ -#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS - -namespace ZeroTier { - -/** - * A signed enumeration of a node's roots (planet and moons) - * - * This is sent as part of HELLO and attests to which roots a node trusts - * to represent it on the network. Federated roots (moons) can send these - * further upstream to tell global roots which nodes they represent, making - * them reachable via federated roots if they are not reachable directly. - * - * As of 1.2.0 this is sent but not used. Right now nodes still always - * announce to planetary roots no matter what. In the future this can be - * used to implement even better fault tolerance for federation for the - * no roots are reachable case as well as a "privacy mode" where federated - * roots can shield nodes entirely and p2p connectivity behind them can - * be disabled. This will be desirable for a number of use cases. - */ -class CertificateOfRepresentation : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COR; } - - CertificateOfRepresentation() - { - memset(this,0,sizeof(CertificateOfRepresentation)); - } - - inline uint32_t id() const { return 0; } - inline uint64_t timestamp() const { return _timestamp; } - inline const Address &representative(const unsigned int i) const { return _reps[i]; } - inline unsigned int repCount() const { return _repCount; } - - inline void clear() - { - memset(this,0,sizeof(CertificateOfRepresentation)); - } - - /** - * Add a representative if space remains - * - * @param r Representative to add - * @return True if representative was added - */ - inline bool addRepresentative(const Address &r) - { - if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) { - _reps[_repCount++] = r; - return true; - } - return false; - } - - /** - * Sign this COR with my identity - * - * @param myIdentity This node's identity - * @param ts COR timestamp for establishing new vs. old - */ - inline void sign(const Identity &myIdentity,const uint64_t ts) - { - _timestamp = ts; - Buffer tmp; - this->serialize(tmp,true); - _signature = myIdentity.sign(tmp.data(),tmp.size()); - } - - /** - * Verify this COR's signature - * - * @param senderIdentity Identity of sender of COR - * @return True if COR is valid - */ - inline bool verify(const Identity &senderIdentity) - { - try { - Buffer tmp; - this->serialize(tmp,true); - return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN); - } catch ( ... ) { - return false; - } - } - - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append((uint64_t)_timestamp); - b.append((uint16_t)_repCount); - for(unsigned int i=0;i<_repCount;++i) - _reps[i].appendTo(b); - - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - - b.append((uint16_t)0); // size of any additional fields, currently 0 - - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - clear(); - - unsigned int p = startAt; - - _timestamp = b.template at(p); p += 8; - const unsigned int rc = b.template at(p); p += 2; - for(unsigned int i=0;i ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc; - - if (b[p++] == 1) { - if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } else { - p += 2 + b.template at(p); - } - - p += 2 + b.template at(p); - if (p > b.size()) - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - - return (p - startAt); - } - -private: - uint64_t _timestamp; - Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES]; - unsigned int _repCount; - C25519::Signature _signature; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Credential.hpp b/node/Credential.hpp index bc81919b..e8767e22 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -56,7 +56,6 @@ public: CREDENTIAL_TYPE_CAPABILITY = 2, CREDENTIAL_TYPE_TAG = 3, CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership - CREDENTIAL_TYPE_COR = 5, // CertificateOfRepresentation CREDENTIAL_TYPE_REVOCATION = 6 }; }; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c0409c91..9b614e37 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -44,7 +44,6 @@ #include "World.hpp" #include "Node.hpp" #include "CertificateOfMembership.hpp" -#include "CertificateOfRepresentation.hpp" #include "Capability.hpp" #include "Tag.hpp" #include "Revocation.hpp" @@ -328,15 +327,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool ptr += 16; } } - - // Certificates of representation (if present) - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } } // Send OK(HELLO) with an echo of the packet's timestamp and some of the same @@ -401,11 +391,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool } outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),now); @@ -460,15 +445,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } } - // Handle certificate of representation if present - if ((ptr + 2) <= size()) { - if (at(ptr) > 0) { - CertificateOfRepresentation cor; - ptr += 2; - ptr += cor.deserialize(*this,ptr); - } else ptr += 2; - } - if (!hops()) peer->addDirectLatencyMeasurment((unsigned int)latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); diff --git a/node/Peer.cpp b/node/Peer.cpp index 60661592..255d4004 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -343,11 +343,6 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA outp.append((uint64_t)0); } - const unsigned int corSizeAt = outp.size(); - outp.addSize(2); - RR->topology->appendCertificateOfRepresentation(outp); - outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2))); - outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); RR->node->expectReplyTo(outp.packetId()); diff --git a/node/Topology.cpp b/node/Topology.cpp index f884e9c3..d5fea569 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -425,13 +425,6 @@ void Topology::_memoizeUpstreams(void *tPtr) } std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); - - _cor.clear(); - for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - if (!_cor.addRepresentative(*a)) - break; - } - _cor.sign(RR->identity,RR->node->now()); } void Topology::_savePeer(void *tPtr,const SharedPtr &peer) diff --git a/node/Topology.hpp b/node/Topology.hpp index c3a218e3..650e5363 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -46,7 +46,6 @@ #include "InetAddress.hpp" #include "Hashtable.hpp" #include "World.hpp" -#include "CertificateOfRepresentation.hpp" namespace ZeroTier { @@ -441,25 +440,6 @@ public: } } - /** - * @return Current certificate of representation (copy) - */ - inline CertificateOfRepresentation certificateOfRepresentation() const - { - Mutex::Lock _l(_upstreams_m); - return _cor; - } - - /** - * @param buf Buffer to receive COR - */ - template - void appendCertificateOfRepresentation(Buffer &buf) - { - Mutex::Lock _l(_upstreams_m); - _cor.serialize(buf); - } - private: Identity _getIdentity(void *tPtr,const Address &zta); void _memoizeUpstreams(void *tPtr); @@ -480,7 +460,6 @@ private: std::vector _moons; std::vector< std::pair > _moonSeeds; std::vector
_upstreamAddresses; - CertificateOfRepresentation _cor; bool _amRoot; Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; diff --git a/node/Trace.cpp b/node/Trace.cpp index 8e78b676..d90c3143 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -32,7 +32,6 @@ #include "Dictionary.hpp" #include "CertificateOfMembership.hpp" #include "CertificateOfOwnership.hpp" -#include "CertificateOfRepresentation.hpp" #include "Tag.hpp" #include "Capability.hpp" #include "Revocation.hpp" @@ -287,18 +286,6 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c, _send(tPtr,d,c.networkId()); } -void Trace::credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); -} - void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason) { Dictionary d; diff --git a/node/Trace.hpp b/node/Trace.hpp index a7b2b194..5ee5b520 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -53,7 +53,6 @@ class NetworkConfig; class MAC; class CertificateOfMembership; class CertificateOfOwnership; -class CertificateOfRepresentation; class Revocation; class Tag; class Capability; @@ -137,7 +136,6 @@ public: void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason); void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason); - void credentialRejected(void *const tPtr,const CertificateOfRepresentation &c,const char *reason); void credentialRejected(void *const tPtr,const Capability &c,const char *reason); void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); -- cgit v1.2.3 From 459f1e7bfb50eb7b491940b7106d8788a7a5e11f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 25 Oct 2017 12:42:14 -0700 Subject: Refactor path stability stuff and add basic multipath support. --- node/Constants.hpp | 10 -- node/Hashtable.hpp | 5 - node/IncomingPacket.cpp | 7 +- node/InetAddress.cpp | 36 +++-- node/InetAddress.hpp | 4 +- node/Node.cpp | 24 ++-- node/Path.hpp | 30 ++++- node/Peer.cpp | 352 ++++++++++++++++++++++++++++++------------------ node/Peer.hpp | 173 ++++++++++-------------- node/Switch.cpp | 81 ++--------- node/Topology.cpp | 2 +- node/Topology.hpp | 2 +- node/Trace.cpp | 5 +- node/Trace.hpp | 2 +- 14 files changed, 375 insertions(+), 358 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 30cd1575..6360a693 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -268,16 +268,6 @@ */ #define ZT_PATH_HEARTBEAT_PERIOD 14000 -/** - * Paths are considered inactive if they have not received traffic in this long - */ -#define ZT_PATH_ALIVE_TIMEOUT 45000 - -/** - * Minimum time between attempts to check dead paths to see if they can be re-awakened - */ -#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500 - /** * Do not accept HELLOs over a given path more often than this */ diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 95a8e74f..e5496592 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -42,11 +42,6 @@ namespace ZeroTier { /** * A minimal hash table implementation for the ZeroTier core - * - * This is not a drop-in replacement for STL containers, and has several - * limitations. Keys can be uint64_t or an object, and if the latter they - * must implement a method called hashCode() that returns an unsigned long - * value that is evenly distributed. */ template class Hashtable diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9b614e37..dfa0a161 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -446,7 +446,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } if (!hops()) - peer->addDirectLatencyMeasurment((unsigned int)latency); + _path->updateLatency((unsigned int)latency); + peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); if ((externalSurfaceAddress)&&(hops() == 0)) @@ -1091,7 +1092,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->redirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path->localSocket(),a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } @@ -1105,7 +1106,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->redirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path->localSocket(),a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index f7585bdb..d3efc089 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -273,29 +273,27 @@ InetAddress InetAddress::network() const return r; } -#ifdef ZT_SDK - bool InetAddress::isEqualPrefix(const InetAddress &addr) const - { - if (addr.ss_family == ss_family) { - switch(ss_family) { - case AF_INET6: { - const InetAddress mask(netmask()); - InetAddress addr_mask(addr.netmask()); - const uint8_t *n = reinterpret_cast(reinterpret_cast(&addr_mask)->sin6_addr.s6_addr); - const uint8_t *m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); - const uint8_t *a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); - const uint8_t *b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(unsigned int i=0;i<16;++i) { - if ((a[i] & m[i]) != (b[i] & n[i])) - return false; - } - return true; +bool InetAddress::isEqualPrefix(const InetAddress &addr) const +{ + if (addr.ss_family == ss_family) { + switch(ss_family) { + case AF_INET6: { + const InetAddress mask(netmask()); + InetAddress addr_mask(addr.netmask()); + const uint8_t *n = reinterpret_cast(reinterpret_cast(&addr_mask)->sin6_addr.s6_addr); + const uint8_t *m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); + const uint8_t *a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); + const uint8_t *b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + for(unsigned int i=0;i<16;++i) { + if ((a[i] & m[i]) != (b[i] & n[i])) + return false; } + return true; } } - return false; } -#endif + return false; +} bool InetAddress::containsAddress(const InetAddress &addr) const { diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 61cdb05e..79bf76ad 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -330,7 +330,6 @@ struct InetAddress : public sockaddr_storage */ InetAddress network() const; -#ifdef ZT_SDK /** * Test whether this IPv6 prefix matches the prefix of a given IPv6 address * @@ -338,8 +337,7 @@ struct InetAddress : public sockaddr_storage * @return True if this IPv6 prefix matches the prefix of a given IPv6 address */ bool isEqualPrefix(const InetAddress &addr) const; -#endif - + /** * Test whether this IP/netmask contains this address * diff --git a/node/Node.cpp b/node/Node.cpp index 31ee8f19..b7dbffc3 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -191,12 +191,13 @@ public: { const std::vector *const upstreamStableEndpoints = _upstreamsToContact.get(p->address()); if (upstreamStableEndpoints) { - bool contacted = false; - // Upstreams must be pinged constantly over both IPv4 and IPv6 to allow // them to perform three way handshake introductions for both stacks. - if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET)) { + const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now); + bool contacted = (sent != 0); + + if ((sent & 0x1) == 0) { // bit 0x1 == IPv4 sent for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { @@ -205,8 +206,9 @@ public: break; } } - } else contacted = true; - if (!p->doPingAndKeepalive(_tPtr,_now,AF_INET6)) { + } + + if ((sent & 0x2) == 0) { // bit 0x2 == IPv6 sent for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { @@ -215,8 +217,10 @@ public: break; } } - } else contacted = true; + } + // If we have no memoized addresses for this upstream peer, attempt to contact + // it indirectly so we will be introduced. if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) @@ -224,9 +228,11 @@ public: } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); - _upstreamsToContact.erase(p->address()); // erase from upstreams to contact so that we can WHOIS those that remain + + _upstreamsToContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain } else if (p->isActive(_now)) { - p->doPingAndKeepalive(_tPtr,_now,-1); + // Regular non-upstream nodes get pinged if they appear active. + p->doPingAndKeepalive(_tPtr,_now); } } @@ -420,7 +426,7 @@ ZT_PeerList *Node::peers() const p->versionMinor = -1; p->versionRev = -1; } - p->latency = pi->second->latency(); + p->latency = pi->second->latency(_now); p->role = RR->topology->role(pi->second->identity().address()); std::vector< SharedPtr > paths(pi->second->paths(_now)); diff --git a/node/Path.hpp b/node/Path.hpp index 050fb6e2..80132c13 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -100,6 +100,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _latency(0xffff), _addr(), _ipScope(InetAddress::IP_SCOPE_NONE) { @@ -117,6 +118,7 @@ public: _incomingLinkQualitySlowLogCounter(-64), // discard first fast log _incomingLinkQualityPreviousPacketCounter(0), _outgoingPacketCounter(0), + _latency(0xffff), _addr(addr), _ipScope(addr.ipScope()) { @@ -188,6 +190,19 @@ public: */ inline void sent(const int64_t t) { _lastOut = t; } + /** + * Update path latency with a new measurement + * + * @param l Measured latency + */ + inline void updateLatency(const unsigned int l) + { + unsigned int pl = _latency; + if (pl < 0xffff) + _latency = (pl + l) / 2; + else _latency = l; + } + /** * @return Local socket as specified by external code */ @@ -259,9 +274,19 @@ public: } /** - * @return True if path appears alive + * @return Latency or 0xffff if unknown */ - inline bool alive(const int64_t now) const { return ((now - _lastIn) <= ZT_PATH_ALIVE_TIMEOUT); } + inline unsigned int latency() const { return _latency; } + + /** + * @return Path quality -- lower is better + */ + inline int quality(const int64_t now) const + { + const int l = (int)_latency; + const int age = (int)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow + return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (int)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); + } /** * @return True if this path needs a heartbeat @@ -300,6 +325,7 @@ private: volatile signed int _incomingLinkQualitySlowLogCounter; volatile unsigned int _incomingLinkQualityPreviousPacketCounter; volatile unsigned int _outgoingPacketCounter; + volatile unsigned int _latency; InetAddress _addr; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often volatile uint8_t _incomingLinkQualitySlowLog[32]; diff --git a/node/Peer.cpp b/node/Peer.cpp index 255d4004..61d8e990 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -52,12 +52,12 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), + _lastSentFullHello(0), _vProto(0), _vMajor(0), _vMinor(0), _vRevision(0), _id(peerIdentity), - _latency(0), _directPathPushCutoffCount(0), _credentialsCutoffCount(0) { @@ -148,59 +148,47 @@ void Peer::received( if (hops == 0) { // If this is a direct packet (no hops), update existing paths or learn new ones - bool pathAlreadyKnown = false; - - { - Mutex::Lock _l(_paths_m); - if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) { - const struct sockaddr_in *const r = reinterpret_cast(&(path->address())); - const struct sockaddr_in *const l = reinterpret_cast(&(_v4Path.p->address())); - if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(path->localSocket() == _v4Path.p->localSocket())) { - _v4Path.lr = now; - pathAlreadyKnown = true; - } - } else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) { - const struct sockaddr_in6 *const r = reinterpret_cast(&(path->address())); - const struct sockaddr_in6 *const l = reinterpret_cast(&(_v6Path.p->address())); - if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(path->localSocket() == _v6Path.p->localSocket())) { - _v6Path.lr = now; - pathAlreadyKnown = true; - } - } - } - - if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address())) ) { - Mutex::Lock _l(_paths_m); + Mutex::Lock _l(_paths_m); - _PeerPath *replacablePath = (_PeerPath *)0; - if (path->address().ss_family == AF_INET) { - if ( ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || (path->preferenceRank() >= _v4Path.p->preferenceRank()) ) && ( (now - _v4Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - replacablePath = &_v4Path; + unsigned int worstQualityPath = 0; + int worstQuality = 0; + bool havePath = false; + for(unsigned int p=0;paddress().ss_family == AF_INET6) { - if ( ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || (path->preferenceRank() >= _v6Path.p->preferenceRank()) ) && ( (now - _v6Path.sticky) > ZT_PEER_PATH_EXPIRATION ) ) { - replacablePath = &_v6Path; + const int q = _paths[p].p->quality(now) / _paths[p].priority; + if (q >= worstQuality) { + worstQuality = q; + worstQualityPath = p; } + } else { + worstQualityPath = p; + break; } + } - if (replacablePath) { - if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(tPtr,networkId,*this,replacablePath->p,path,packetId); - replacablePath->lr = now; - replacablePath->p = path; - } else { - RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); - } + if ((!havePath)&&(RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()))) { + if (verb == Packet::VERB_OK) { + RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[worstQualityPath].p,path,packetId); + _paths[worstQualityPath].lr = now; + _paths[worstQualityPath].p = path; + _paths[worstQualityPath].priority = 1; + } else { + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + path->sent(now); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); } } } - // If we are being relayed or if we're using a global address, send PUSH_DIRECT_PATHS. - // In the global address case we push only configured direct paths to accomplish - // fall-forward to local backplane networks over e.g. LAN or Amazon VPC. - if ( ((hops > 0)||(path->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) && (this->trustEstablished(now)) ) { + // If we have a trust relationship periodically push a message enumerating + // all known external addresses for ourselves. We now do this even if we + // have a current path since we'll want to use new ones too. + if (this->trustEstablished(now)) { if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; @@ -210,6 +198,7 @@ void Peer::received( for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) pathsToPush.push_back(*i); + // Do symmetric NAT prediction if we are communicating indirectly. if (hops > 0) { std::vector sym(RR->sa->getSymmetricNatPredictions()); for(unsigned long i=0,added=0;i Peer::getBestPath(int64_t now,bool includeExpired) const { Mutex::Lock _l(_paths_m); - int64_t v6lr = 0; - if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) - v6lr = _v6Path.p->lastIn(); - int64_t v4lr = 0; - if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) - v4lr = _v4Path.p->lastIn(); - - if ( (v6lr > v4lr) && ((now - v6lr) < ZT_PATH_ALIVE_TIMEOUT) ) { - return _v6Path.p->send(RR,tPtr,data,len,now); - } else if ((now - v4lr) < ZT_PATH_ALIVE_TIMEOUT) { - return _v4Path.p->send(RR,tPtr,data,len,now); - } else if (force) { - if (v6lr > v4lr) { - return _v6Path.p->send(RR,tPtr,data,len,now); - } else if (v4lr) { - return _v4Path.p->send(RR,tPtr,data,len,now); - } + unsigned int bestPath = ZT_PEER_MAX_PATHS; + int bestPathQuality = 2147483647; // INT_MAX + for(unsigned int i=0;iquality(now) / _paths[i].priority; + if (q < bestPathQuality) { + bestPathQuality = q; + bestPath = i; + } + } + } else break; } - return false; + if (bestPath != ZT_PEER_MAX_PATHS) + return _paths[bestPath].p; + return SharedPtr(); } -SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) +void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &other) const { - Mutex::Lock _l(_paths_m); + unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + int theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { + myBestV4ByScope[i] = ZT_PEER_MAX_PATHS; + myBestV6ByScope[i] = ZT_PEER_MAX_PATHS; + myBestV4QualityByScope[i] = 2147483647; + myBestV6QualityByScope[i] = 2147483647; + theirBestV4ByScope[i] = ZT_PEER_MAX_PATHS; + theirBestV6ByScope[i] = ZT_PEER_MAX_PATHS; + theirBestV4QualityByScope[i] = 2147483647; + theirBestV6QualityByScope[i] = 2147483647; + } - int64_t v6lr = 0; - if ((includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v6Path.p)) { - v6lr = _v6Path.p->lastIn(); + Mutex::Lock _l1(_paths_m); + + for(unsigned int i=0;iquality(now) / _paths[i].priority; + const unsigned int s = (unsigned int)_paths[i].p->ipScope(); + switch(_paths[i].p->address().ss_family) { + case AF_INET: + if (q < myBestV4QualityByScope[s]) { + myBestV4QualityByScope[s] = q; + myBestV4ByScope[s] = i; + } + break; + case AF_INET6: + if (q < myBestV6QualityByScope[s]) { + myBestV6QualityByScope[s] = q; + myBestV6ByScope[s] = i; + } + break; + } + } else break; } - int64_t v4lr = 0; - if ((includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)) && (_v4Path.p)) { - v4lr = _v4Path.p->lastIn(); + + Mutex::Lock _l2(other->_paths_m); + + for(unsigned int i=0;i_paths[i].p) { + const int q = other->_paths[i].p->quality(now) / other->_paths[i].priority; + const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); + switch(other->_paths[i].p->address().ss_family) { + case AF_INET: + if (q < theirBestV4QualityByScope[s]) { + theirBestV4QualityByScope[s] = q; + theirBestV4ByScope[s] = i; + } + break; + case AF_INET6: + if (q < theirBestV6QualityByScope[s]) { + theirBestV6QualityByScope[s] = q; + theirBestV6ByScope[s] = i; + } + break; + } + } else break; } - if (v6lr > v4lr) { - return _v6Path.p; - } else if (v4lr) { - return _v4Path.p; + unsigned int mine = ZT_PEER_MAX_PATHS; + unsigned int theirs = ZT_PEER_MAX_PATHS; + + for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) { + if ((myBestV6ByScope[s] != ZT_PEER_MAX_PATHS)&&(theirBestV6ByScope[s] != ZT_PEER_MAX_PATHS)) { + mine = myBestV6ByScope[s]; + theirs = theirBestV6ByScope[s]; + break; + } + if ((myBestV4ByScope[s] != ZT_PEER_MAX_PATHS)&&(theirBestV4ByScope[s] != ZT_PEER_MAX_PATHS)) { + mine = myBestV4ByScope[s]; + theirs = theirBestV4ByScope[s]; + break; + } } - return SharedPtr(); + if (mine != ZT_PEER_MAX_PATHS) { + unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons + const unsigned int completed = alt + 2; + while (alt != completed) { + if ((alt & 1) == 0) { + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + other->_id.address().appendTo(outp); + outp.append((uint16_t)other->_paths[theirs].p->address().port()); + if (other->_paths[theirs].p->address().ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(other->_paths[theirs].p->address().rawIpData(),16); + } else { + outp.append((uint8_t)4); + outp.append(other->_paths[theirs].p->address().rawIpData(),4); + } + outp.armor(_key,true,_paths[mine].p->nextOutgoingCounter()); + _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); + } else { + Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + _id.address().appendTo(outp); + outp.append((uint16_t)_paths[mine].p->address().port()); + if (_paths[mine].p->address().ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(_paths[mine].p->address().rawIpData(),16); + } else { + outp.append((uint8_t)4); + outp.append(_paths[mine].p->address().rawIpData(),4); + } + outp.armor(other->_key,true,other->_paths[theirs].p->nextOutgoingCounter()); + other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); + } + ++alt; + } + } } void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter) @@ -377,76 +462,83 @@ void Peer::tryMemorizedPath(void *tPtr,int64_t now) } } -bool Peer::doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily) +unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) { + unsigned int sent = 0; + Mutex::Lock _l(_paths_m); - if (inetAddressFamily < 0) { - int64_t v6lr = 0; - if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) ) - v6lr = _v6Path.p->lastIn(); - int64_t v4lr = 0; - if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) ) - v4lr = _v4Path.p->lastIn(); - - if (v6lr > v4lr) { - if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); - _v6Path.p->sent(now); - return true; - } - } else if (v4lr) { - if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); - _v4Path.p->sent(now); - return true; - } - } - } else { - if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { - if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); - _v4Path.p->sent(now); - return true; - } - } else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) { - if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) { - attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); - _v6Path.p->sent(now); - return true; + const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD); + _lastSentFullHello = now; + + unsigned int j = 0; + for(unsigned int i=0;ineedsHeartbeat(now))) { + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); + _paths[i].p->sent(now); + sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; } + if (i != j) + _paths[j] = _paths[i]; + ++j; } } + while(j < ZT_PEER_MAX_PATHS) { + _paths[j].lr = 0; + _paths[j].p.zero(); + _paths[j].priority = 1; + ++j; + } - return false; + return sent; } -void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) +void Peer::clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) { - if ((remoteAddress.ss_family != AF_INET)&&(remoteAddress.ss_family != AF_INET6)) // sanity check - return; - - SharedPtr op; SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); - np->received(now); + RR->t->peerRedirected(tPtr,0,*this,np); attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); - { Mutex::Lock _l(_paths_m); - if (remoteAddress.ss_family == AF_INET) { - op = _v4Path.p; - _v4Path.lr = now; - _v4Path.sticky = now; - _v4Path.p = np; - } else if (remoteAddress.ss_family == AF_INET6) { - op = _v6Path.p; - _v6Path.lr = now; - _v6Path.sticky = now; - _v6Path.p = np; + int worstQuality = 0; + unsigned int worstQualityPath = 0; + for(unsigned int i=0;iquality(now) / _paths[i].priority; + if (q >= worstQuality) { + worstQuality = q; + worstQualityPath = i; + } + } else { + worstQualityPath = i; + break; + } } + _paths[worstQualityPath].lr = now; + _paths[worstQualityPath].p = np; + _paths[worstQualityPath].priority = 6; // 1 + 5 } +} - RR->t->peerRedirected(tPtr,0,*this,op,np); +void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) +{ + Mutex::Lock _l(_paths_m); + for(unsigned int i=0;iaddress().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false,_paths[i].p->nextOutgoingCounter()); + _paths[i].p->sent(now); + _paths[i].lr = 0; // path will not be used unless it speaks again + } + } else break; + } } } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index e08f7d36..c236a2cd 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -53,6 +53,15 @@ #define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) +/** + * Maximum number of direct paths to a peer + * + * This can be increased. You'll want about 2X the number of physical links + * you are ever likely to want to bundle/trunk since there is likely to be + * a path for every protocol (IPv4, IPv6, etc.). + */ +#define ZT_PEER_MAX_PATHS 16 + namespace ZeroTier { /** @@ -116,6 +125,8 @@ public: const uint64_t networkId); /** + * Check whether we have an active path to this peer via the given address + * * @param now Current time * @param addr Remote address * @return True if we have an active path to this destination @@ -123,7 +134,13 @@ public: inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); - return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) ); + for(unsigned int i=0;iaddress() == addr)) + return true; + } else break; + } + return false; } /** @@ -136,19 +153,27 @@ public: * @param force If true, send even if path is not alive * @return True if we actually sent something */ - bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force); + inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force) + { + SharedPtr bp(getBestPath(now,force)); + if (bp) + return bp->send(RR,tPtr,data,len,now); + return false; + } /** * Get the best current direct path * - * This does not check Path::alive(), but does return the most recently - * active path and does check expiration (which is a longer timeout). - * * @param now Current time * @param includeExpired If true, include even expired paths * @return Best current path or NULL if none */ - SharedPtr getBestPath(int64_t now,bool includeExpired); + SharedPtr getBestPath(int64_t now,bool includeExpired) const; + + /** + * Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path + */ + void introduce(void *const tPtr,const int64_t now,const SharedPtr &other) const; /** * Send a HELLO to this peer at a specified physical address @@ -190,67 +215,39 @@ public: /** * Send pings or keepalives depending on configured timeouts * + * This also cleans up some internal data structures. It's called periodically from Node. + * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param now Current time * @param inetAddressFamily Keep this address family alive, or -1 for any - * @return True if we have at least one direct path of the given family (or any if family is -1) + * @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent) */ - bool doPingAndKeepalive(void *tPtr,int64_t now,int inetAddressFamily); + unsigned int doPingAndKeepalive(void *tPtr,int64_t now); /** - * Specify remote path for this peer and forget others - * - * This overrides normal path learning and tells this peer to be found - * at this address, at least within the address's family. Other address - * families are not modified. + * Process a cluster redirect sent by this peer * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param localSocket Local socket as supplied by external code * @param remoteAddress Remote address * @param now Current time */ - void redirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); + void clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); /** * Reset paths within a given IP scope and address family * * Resetting a path involves sending an ECHO to it and then deactivating - * it until or unless it responds. + * it until or unless it responds. This is done when we detect a change + * to our external IP or another system change that might invalidate + * many or all current paths. * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param scope IP scope * @param inetAddressFamily Family e.g. AF_INET * @param now Current time */ - inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) - { - Mutex::Lock _l(_paths_m); - if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v4Path.p->localSocket(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter()); - _v4Path.p->sent(now); - _v4Path.lr = 0; // path will not be used unless it speaks again - } else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) { - attemptToContactAt(tPtr,_v6Path.p->localSocket(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter()); - _v6Path.p->sent(now); - _v6Path.lr = 0; // path will not be used unless it speaks again - } - } - - /** - * Fill parameters with V4 and V6 addresses if known and alive - * - * @param now Current time - * @param v4 Result parameter to receive active IPv4 address, if any - * @param v6 Result parameter to receive active IPv6 address, if any - */ - inline void getRendezvousAddresses(int64_t now,InetAddress &v4,InetAddress &v6) const - { - Mutex::Lock _l(_paths_m); - if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) - v4 = _v4Path.p->address(); - if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) - v6 = _v6Path.p->address(); - } + void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now); /** * @param now Current time @@ -260,10 +257,10 @@ public: { std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); - if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now))) - pp.push_back(_v4Path.p); - if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now))) - pp.push_back(_v6Path.p); + for(unsigned int i=0;i bp(getBestPath(now,false)); + return ((bp) ? bp->latency() : 0xffff); + } /** * This computes a quality score for relays and root servers @@ -303,25 +304,12 @@ public: const uint64_t tsr = now - _lastReceive; if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) return (~(unsigned int)0); - unsigned int l = _latency; + unsigned int l = latency(now); if (!l) l = 0xffff; return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1)); } - /** - * Update latency with a new direct measurment - * - * @param l Direct latency measurment in ms - */ - inline void addDirectLatencyMeasurment(unsigned int l) - { - unsigned int ol = _latency; - if ((ol > 0)&&(ol < 10000)) - _latency = (ol + std::min(l,(unsigned int)65535)) / 2; - else _latency = std::min(l,(unsigned int)65535); - } - /** * @return 256-bit secret symmetric encryption key */ @@ -442,29 +430,15 @@ public: /** * Serialize a peer for storage in local cache * - * This does not serialize everything, just identity and addresses where the peer - * may be reached. + * This does not serialize everything, just non-ephemeral information. */ template - inline void serialize(Buffer &b) const + inline void serializeForCache(Buffer &b) const { - b.append((uint8_t)0); + b.append((uint8_t)1); _id.serialize(b); - b.append(_lastReceive); - b.append(_lastNontrivialReceive); - b.append(_lastTriedMemorizedPath); - b.append(_lastDirectPathPushSent); - b.append(_lastDirectPathPushReceive); - b.append(_lastCredentialRequestSent); - b.append(_lastWhoisRequestReceived); - b.append(_lastEchoRequestReceived); - b.append(_lastComRequestReceived); - b.append(_lastComRequestSent); - b.append(_lastCredentialsReceived); - b.append(_lastTrustEstablishedPacketReceived); - b.append((uint16_t)_vProto); b.append((uint16_t)_vMajor); b.append((uint16_t)_vMinor); @@ -472,15 +446,16 @@ public: { Mutex::Lock _l(_paths_m); - unsigned int pcount = 0; - if (_v4Path.p) ++pcount; - if (_v6Path.p) ++pcount; - b.append((uint8_t)pcount); - if (_v4Path.p) _v4Path.p->address().serialize(b); - if (_v6Path.p) _v6Path.p->address().serialize(b); + unsigned int pc = 0; + for(unsigned int i=0;iaddress().serialize(b); } - - b.append((uint16_t)0); } template @@ -488,7 +463,7 @@ public: { try { unsigned int ptr = 0; - if (b[ptr++] != 0) + if (b[ptr++] != 1) return SharedPtr(); Identity id; @@ -498,15 +473,16 @@ public: SharedPtr p(new Peer(renv,renv->identity,id)); - ptr += 12 * 8; // skip deserializing ephemeral state in this case - p->_vProto = b.template at(ptr); ptr += 2; p->_vMajor = b.template at(ptr); ptr += 2; p->_vMinor = b.template at(ptr); ptr += 2; p->_vRevision = b.template at(ptr); ptr += 2; - const unsigned int pcount = (unsigned int)b[ptr++]; - for(unsigned int i=0;i(ptr); ptr += 2; + for(unsigned int i=0;i p; + int priority; // >= 1, higher is better }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; @@ -548,19 +524,18 @@ private: int64_t _lastComRequestSent; int64_t _lastCredentialsReceived; int64_t _lastTrustEstablishedPacketReceived; + int64_t _lastSentFullHello; uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; uint16_t _vRevision; - _PeerPath _v4Path; // IPv4 direct path - _PeerPath _v6Path; // IPv6 direct path + _PeerPath _paths[ZT_PEER_MAX_PATHS]; Mutex _paths_m; Identity _id; - unsigned int _latency; unsigned int _directPathPushCutoffCount; unsigned int _credentialsCutoffCount; diff --git a/node/Switch.cpp b/node/Switch.cpp index cc022b6b..a8cf0ce6 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -169,68 +169,22 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if (packet.hops() < ZT_RELAY_MAX_HOPS) { packet.incrementHops(); - SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { - if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { // don't send RENDEZVOUS for cluster frontplane relays - const InetAddress *hintToSource = (InetAddress *)0; - const InetAddress *hintToDest = (InetAddress *)0; - - InetAddress destV4,destV6; - InetAddress sourceV4,sourceV6; - relayTo->getRendezvousAddresses(now,destV4,destV6); - + if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); - if (sourcePeer) { - sourcePeer->getRendezvousAddresses(now,sourceV4,sourceV6); - if ((destV6)&&(sourceV6)) { - hintToSource = &destV6; - hintToDest = &sourceV6; - } else if ((destV4)&&(sourceV4)) { - hintToSource = &destV4; - hintToDest = &sourceV4; - } - - if ((hintToSource)&&(hintToDest)) { - unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for obscure NAT-t reasons - const unsigned int completed = alt + 2; - while (alt != completed) { - if ((alt & 1) == 0) { - Packet outp(source,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - destination.appendTo(outp); - outp.append((uint16_t)hintToSource->port()); - if (hintToSource->ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(hintToSource->rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(hintToSource->rawIpData(),4); - } - send(tPtr,outp,true); - } else { - Packet outp(destination,RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - source.appendTo(outp); - outp.append((uint16_t)hintToDest->port()); - if (hintToDest->ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(hintToDest->rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(hintToDest->rawIpData(),4); - } - send(tPtr,outp,true); - } - ++alt; - } - } - } + if (sourcePeer) + relayTo->introduce(tPtr,now,sourcePeer); } } else { relayTo = RR->topology->getUpstreamPeer(); - if ((relayTo)&&(relayTo->address() != source)) - relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); + if ((relayTo)&&(relayTo->address() != source)) { + if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) { + const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); + if (sourcePeer) + relayTo->introduce(tPtr,now,sourcePeer); + } + } } } } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { @@ -694,22 +648,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); if (peer) { - /* First get the best path, and if it's dead (and this is not a root) - * we attempt to re-activate that path but this packet will flow - * upstream. If the path comes back alive, it will be used in the future. - * For roots we don't do the alive check since roots are not required - * to send heartbeats "down" and because we have to at least try to - * go somewhere. */ - viaPath = peer->getBestPath(now,false); - if ( (viaPath) && (!viaPath->alive(now)) && (!RR->topology->isUpstream(peer->identity())) ) { - if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(int64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) { - peer->attemptToContactAt(tPtr,viaPath->localSocket(),viaPath->address(),now,false,viaPath->nextOutgoingCounter()); - viaPath->sent(now); - } - viaPath.zero(); - } - if (!viaPath) { peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known const SharedPtr relay(RR->topology->getUpstreamPeer()); diff --git a/node/Topology.cpp b/node/Topology.cpp index d5fea569..d1b389df 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -431,7 +431,7 @@ void Topology::_savePeer(void *tPtr,const SharedPtr &peer) { try { Buffer buf; - peer->serialize(buf); + peer->serializeForCache(buf); uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0; RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); } catch ( ... ) {} // sanity check, discard invalid entries diff --git a/node/Topology.hpp b/node/Topology.hpp index 650e5363..b09f95cf 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -300,7 +300,7 @@ public: SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { const SharedPtr pp((*p)->getBestPath(now,false)); - if ((pp)&&(pp->alive(now))) + if (pp) ++cnt; } return cnt; diff --git a/node/Trace.cpp b/node/Trace.cpp index d90c3143..6d85942d 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -92,16 +92,13 @@ void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &p _send(tPtr,d,networkId); } -void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath) +void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath) { char tmp[128]; Dictionary d; d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - if (oldPath) { - d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); - } if (newPath) { d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); diff --git a/node/Trace.hpp b/node/Trace.hpp index 5ee5b520..4192d1c2 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -105,7 +105,7 @@ public: void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); - void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); + void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath); void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); -- cgit v1.2.3 From 71bdaa95087536954f1f1cb7b4652fd9b33be587 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 25 Oct 2017 13:27:28 -0700 Subject: Now with more worky. --- include/ZeroTierOne.h | 6 +++--- node/Node.cpp | 2 ++ node/Peer.cpp | 48 ++++++++++++++++++++++++------------------------ node/Peer.hpp | 21 +++++++-------------- 4 files changed, 36 insertions(+), 41 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 02bb283b..16668534 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -173,7 +173,7 @@ extern "C" { /** * Maximum number of direct network paths to a given peer */ -#define ZT_MAX_PEER_NETWORK_PATHS 4 +#define ZT_MAX_PEER_NETWORK_PATHS 16 /** * Maximum number of path configurations that can be set @@ -1228,9 +1228,9 @@ typedef struct int versionRev; /** - * Last measured latency in milliseconds or zero if unknown + * Last measured latency in milliseconds or -1 if unknown */ - unsigned int latency; + int latency; /** * What trust hierarchy role does this device have? diff --git a/node/Node.cpp b/node/Node.cpp index b7dbffc3..f0fcb4d7 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -427,6 +427,8 @@ ZT_PeerList *Node::peers() const p->versionRev = -1; } p->latency = pi->second->latency(_now); + if (p->latency >= 0xffff) + p->latency = -1; p->role = RR->topology->role(pi->second->identity().address()); std::vector< SharedPtr > paths(pi->second->paths(_now)); diff --git a/node/Peer.cpp b/node/Peer.cpp index 61d8e990..d2692011 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -153,7 +153,7 @@ void Peer::received( unsigned int worstQualityPath = 0; int worstQuality = 0; bool havePath = false; - for(unsigned int p=0;p Peer::getBestPath(int64_t now,bool includeExpired) const { Mutex::Lock _l(_paths_m); - unsigned int bestPath = ZT_PEER_MAX_PATHS; + unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; int bestPathQuality = 2147483647; // INT_MAX - for(unsigned int i=0;iquality(now) / _paths[i].priority; - if (q < bestPathQuality) { + if (q <= bestPathQuality) { bestPathQuality = q; bestPath = i; } @@ -271,7 +271,7 @@ SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) const } else break; } - if (bestPath != ZT_PEER_MAX_PATHS) + if (bestPath != ZT_MAX_PEER_NETWORK_PATHS) return _paths[bestPath].p; return SharedPtr(); } @@ -287,31 +287,31 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o int theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; int theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { - myBestV4ByScope[i] = ZT_PEER_MAX_PATHS; - myBestV6ByScope[i] = ZT_PEER_MAX_PATHS; + myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; + myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV4QualityByScope[i] = 2147483647; myBestV6QualityByScope[i] = 2147483647; - theirBestV4ByScope[i] = ZT_PEER_MAX_PATHS; - theirBestV6ByScope[i] = ZT_PEER_MAX_PATHS; + theirBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; + theirBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; theirBestV4QualityByScope[i] = 2147483647; theirBestV6QualityByScope[i] = 2147483647; } Mutex::Lock _l1(_paths_m); - for(unsigned int i=0;iquality(now) / _paths[i].priority; const unsigned int s = (unsigned int)_paths[i].p->ipScope(); switch(_paths[i].p->address().ss_family) { case AF_INET: - if (q < myBestV4QualityByScope[s]) { + if (q <= myBestV4QualityByScope[s]) { myBestV4QualityByScope[s] = q; myBestV4ByScope[s] = i; } break; case AF_INET6: - if (q < myBestV6QualityByScope[s]) { + if (q <= myBestV6QualityByScope[s]) { myBestV6QualityByScope[s] = q; myBestV6ByScope[s] = i; } @@ -322,19 +322,19 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o Mutex::Lock _l2(other->_paths_m); - for(unsigned int i=0;i_paths[i].p) { const int q = other->_paths[i].p->quality(now) / other->_paths[i].priority; const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); switch(other->_paths[i].p->address().ss_family) { case AF_INET: - if (q < theirBestV4QualityByScope[s]) { + if (q <= theirBestV4QualityByScope[s]) { theirBestV4QualityByScope[s] = q; theirBestV4ByScope[s] = i; } break; case AF_INET6: - if (q < theirBestV6QualityByScope[s]) { + if (q <= theirBestV6QualityByScope[s]) { theirBestV6QualityByScope[s] = q; theirBestV6ByScope[s] = i; } @@ -343,23 +343,23 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } else break; } - unsigned int mine = ZT_PEER_MAX_PATHS; - unsigned int theirs = ZT_PEER_MAX_PATHS; + unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS; + unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS; for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) { - if ((myBestV6ByScope[s] != ZT_PEER_MAX_PATHS)&&(theirBestV6ByScope[s] != ZT_PEER_MAX_PATHS)) { + if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { mine = myBestV6ByScope[s]; theirs = theirBestV6ByScope[s]; break; } - if ((myBestV4ByScope[s] != ZT_PEER_MAX_PATHS)&&(theirBestV4ByScope[s] != ZT_PEER_MAX_PATHS)) { + if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { mine = myBestV4ByScope[s]; theirs = theirBestV4ByScope[s]; break; } } - if (mine != ZT_PEER_MAX_PATHS) { + if (mine != ZT_MAX_PEER_NETWORK_PATHS) { unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons const unsigned int completed = alt + 2; while (alt != completed) { @@ -472,7 +472,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) _lastSentFullHello = now; unsigned int j = 0; - for(unsigned int i=0;ineedsHeartbeat(now))) { @@ -485,7 +485,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) ++j; } } - while(j < ZT_PEER_MAX_PATHS) { + while(j < ZT_MAX_PEER_NETWORK_PATHS) { _paths[j].lr = 0; _paths[j].p.zero(); _paths[j].priority = 1; @@ -504,7 +504,7 @@ void Peer::clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddres Mutex::Lock _l(_paths_m); int worstQuality = 0; unsigned int worstQualityPath = 0; - for(unsigned int i=0;iaddress().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false,_paths[i].p->nextOutgoingCounter()); diff --git a/node/Peer.hpp b/node/Peer.hpp index c236a2cd..997c44f5 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -53,15 +53,6 @@ #define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) -/** - * Maximum number of direct paths to a peer - * - * This can be increased. You'll want about 2X the number of physical links - * you are ever likely to want to bundle/trunk since there is likely to be - * a path for every protocol (IPv4, IPv6, etc.). - */ -#define ZT_PEER_MAX_PATHS 16 - namespace ZeroTier { /** @@ -134,7 +125,7 @@ public: inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const { Mutex::Lock _l(_paths_m); - for(unsigned int i=0;iaddress() == addr)) return true; @@ -257,7 +248,7 @@ public: { std::vector< SharedPtr > pp; Mutex::Lock _l(_paths_m); - for(unsigned int i=0;i bp(getBestPath(now,false)); - return ((bp) ? bp->latency() : 0xffff); + if (bp) + return bp->latency(); + return 0xffff; } /** @@ -447,7 +440,7 @@ public: { Mutex::Lock _l(_paths_m); unsigned int pc = 0; - for(unsigned int i=0;i Date: Wed, 25 Oct 2017 15:44:10 -0700 Subject: A few fixes for cluster mode. --- node/IncomingPacket.cpp | 4 +- node/Path.hpp | 13 ++-- node/Peer.cpp | 183 +++++++++++++++++++++++++++++++----------------- node/Peer.hpp | 6 +- 4 files changed, 133 insertions(+), 73 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index dfa0a161..d44e3b54 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1092,7 +1092,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->clusterRedirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } @@ -1106,7 +1106,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path { if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->clusterRedirect(tPtr,_path->localSocket(),a,now); + peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); } diff --git a/node/Path.hpp b/node/Path.hpp index 80132c13..ab52ced6 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -281,13 +281,18 @@ public: /** * @return Path quality -- lower is better */ - inline int quality(const int64_t now) const + inline long quality(const int64_t now) const { - const int l = (int)_latency; - const int age = (int)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow - return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (int)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); + const int l = (long)_latency; + const int age = (long)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow + return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); } + /** + * @return True if this path is alive (receiving heartbeats) + */ + inline bool alive(const int64_t now) const { return ((now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000)); } + /** * @return True if this path needs a heartbeat */ diff --git a/node/Peer.cpp b/node/Peer.cpp index d2692011..d68e0df3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -148,39 +148,64 @@ void Peer::received( if (hops == 0) { // If this is a direct packet (no hops), update existing paths or learn new ones - Mutex::Lock _l(_paths_m); - unsigned int worstQualityPath = 0; - int worstQuality = 0; bool havePath = false; - for(unsigned int p=0;pquality(now) / _paths[p].priority; - if (q >= worstQuality) { - worstQuality = q; - worstQualityPath = p; - } - } else { - worstQualityPath = p; - break; + { + Mutex::Lock _l(_paths_m); + for(unsigned int i=0;inode->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()))) { - if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[worstQualityPath].p,path,packetId); - _paths[worstQualityPath].lr = now; - _paths[worstQualityPath].p = path; - _paths[worstQualityPath].priority = 1; - } else { - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); - RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); + Mutex::Lock _l(_paths_m); + + // Paths are redunant if they duplicate an alive path to the same IP or + // with the same local socket and address family. + bool redundant = false; + for(unsigned int i=0;ialive(now)) && ( ((_paths[i].p->localSocket() == path->localSocket())&&(_paths[i].p->address().ss_family == path->address().ss_family)) || (_paths[i].p->address().ipsEqual(path->address())) ) ) { + redundant = true; + break; + } + } else break; + } + + if (!redundant) { + unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS; + int replacePathQuality = 0; + for(unsigned int i=0;iquality(now); + if (q > replacePathQuality) { + replacePathQuality = q; + replacePath = i; + } + } else { + replacePath = i; + break; + } + } + + if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) { + if (verb == Packet::VERB_OK) { + RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[replacePath].p,path,packetId); + _paths[replacePath].lr = now; + _paths[replacePath].p = path; + _paths[replacePath].priority = 1; + } else { + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + path->sent(now); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); + } + } } } } @@ -258,11 +283,11 @@ SharedPtr Peer::getBestPath(int64_t now,bool includeExpired) const Mutex::Lock _l(_paths_m); unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; - int bestPathQuality = 2147483647; // INT_MAX + long bestPathQuality = 2147483647; for(unsigned int i=0;iquality(now) / _paths[i].priority; + const long q = _paths[i].p->quality(now) / _paths[i].priority; if (q <= bestPathQuality) { bestPathQuality = q; bestPath = i; @@ -280,12 +305,12 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o { unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - int theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; + long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; @@ -301,7 +326,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o for(unsigned int i=0;iquality(now) / _paths[i].priority; + const long q = _paths[i].p->quality(now) / _paths[i].priority; const unsigned int s = (unsigned int)_paths[i].p->ipScope(); switch(_paths[i].p->address().ss_family) { case AF_INET: @@ -324,7 +349,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o for(unsigned int i=0;i_paths[i].p) { - const int q = other->_paths[i].p->quality(now) / other->_paths[i].priority; + const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority; const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); switch(other->_paths[i].p->address().ss_family) { case AF_INET: @@ -471,19 +496,32 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD); _lastSentFullHello = now; + // Right now we only keep pinging links that have the maximum priority. The + // priority is used to track cluster redirections, meaning that when a cluster + // redirects us its redirect target links override all other links and we + // let those old links expire. + long maxPriority = 0; + for(unsigned int i=0;ineedsHeartbeat(now))) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); - _paths[i].p->sent(now); - sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; + if (_paths[i].p) { + // Clean expired and reduced priority paths + if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) { + if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) { + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); + _paths[i].p->sent(now); + sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; + } + if (i != j) + _paths[j] = _paths[i]; + ++j; } - if (i != j) - _paths[j] = _paths[i]; - ++j; - } + } else break; } while(j < ZT_MAX_PEER_NETWORK_PATHS) { _paths[j].lr = 0; @@ -495,35 +533,52 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) return sent; } -void Peer::clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now) +void Peer::clusterRedirect(void *tPtr,const SharedPtr &originatingPath,const InetAddress &remoteAddress,const int64_t now) { - SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + SharedPtr np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress)); RR->t->peerRedirected(tPtr,0,*this,np); - attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); + + attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true,np->nextOutgoingCounter()); + { Mutex::Lock _l(_paths_m); - int worstQuality = 0; - unsigned int worstQualityPath = 0; + + // New priority is higher than the priority of the originating path (if known) + long newPriority = 1; for(unsigned int i=0;iquality(now) / _paths[i].priority; - if (q >= worstQuality) { - worstQuality = q; - worstQualityPath = i; + } else break; + } + newPriority += 2; + + // Erase any paths with lower priority than this one or that are duplicate + // IPs and add this path. + unsigned int j = 0; + for(unsigned int i=0;i= newPriority)&&(!_paths[i].p->address().ipsEqual(remoteAddress))) { + if (i != j) + _paths[j] = _paths[i]; + ++j; } - } else { - worstQualityPath = i; - break; } } - _paths[worstQualityPath].lr = now; - _paths[worstQualityPath].p = np; - _paths[worstQualityPath].priority = 6; // 1 + 5 + if (j < ZT_MAX_PEER_NETWORK_PATHS) { + _paths[j].lr = now; + _paths[j].p = np; + _paths[j].priority = newPriority; + ++j; + while (j < ZT_MAX_PEER_NETWORK_PATHS) { + _paths[j].lr = 0; + _paths[j].p.zero(); + _paths[j].priority = 1; + ++j; + } + } } } diff --git a/node/Peer.hpp b/node/Peer.hpp index 997c44f5..53b916ab 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -219,11 +219,11 @@ public: * Process a cluster redirect sent by this peer * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localSocket Local socket as supplied by external code + * @param originatingPath Path from which redirect originated * @param remoteAddress Remote address * @param now Current time */ - void clusterRedirect(void *tPtr,const int64_t localSocket,const InetAddress &remoteAddress,const int64_t now); + void clusterRedirect(void *tPtr,const SharedPtr &originatingPath,const InetAddress &remoteAddress,const int64_t now); /** * Reset paths within a given IP scope and address family @@ -498,7 +498,7 @@ private: _PeerPath() : lr(0),p(),priority(1) {} int64_t lr; // time of last valid ZeroTier packet SharedPtr p; - int priority; // >= 1, higher is better + long priority; // >= 1, higher is better }; uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH]; -- cgit v1.2.3 From fac7dc9c913a94550692c31ca6c24fa4db5b5b52 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 25 Oct 2017 16:01:36 -0700 Subject: Stop duplciate IPv6 addresses due to privacy mode IPs. --- node/InetAddress.hpp | 20 ++++++++++++++++++++ node/Peer.cpp | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'node/Peer.cpp') diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 79bf76ad..c1ea6c13 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -405,6 +405,26 @@ struct InetAddress : public sockaddr_storage return false; } + /** + * Performs an IP-only comparison or, if that is impossible, a memcmp() + * + * This version compares only the first 64 bits of IPv6 addresses. + * + * @param a InetAddress to compare again + * @return True if only IP portions are equal (false for non-IP or null addresses) + */ + inline bool ipsEqual2(const InetAddress &a) const + { + if (ss_family == a.ss_family) { + if (ss_family == AF_INET) + return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); + if (ss_family == AF_INET6) + return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,8) == 0); + return (memcmp(this,&a,sizeof(InetAddress)) == 0); + } + return false; + } + inline unsigned long hashCode() const { if (ss_family == AF_INET) { diff --git a/node/Peer.cpp b/node/Peer.cpp index d68e0df3..a3682a97 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -171,7 +171,7 @@ void Peer::received( bool redundant = false; for(unsigned int i=0;ialive(now)) && ( ((_paths[i].p->localSocket() == path->localSocket())&&(_paths[i].p->address().ss_family == path->address().ss_family)) || (_paths[i].p->address().ipsEqual(path->address())) ) ) { + if ( (_paths[i].p->alive(now)) && ( ((_paths[i].p->localSocket() == path->localSocket())&&(_paths[i].p->address().ss_family == path->address().ss_family)) || (_paths[i].p->address().ipsEqual2(path->address())) ) ) { redundant = true; break; } @@ -560,7 +560,7 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr &originatingPath,con unsigned int j = 0; for(unsigned int i=0;i= newPriority)&&(!_paths[i].p->address().ipsEqual(remoteAddress))) { + if ((_paths[i].priority >= newPriority)&&(!_paths[i].p->address().ipsEqual2(remoteAddress))) { if (i != j) _paths[j] = _paths[i]; ++j; -- cgit v1.2.3 From 4166d8ca35ded34180d60b56105a853dd6b02ff4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 8 Nov 2017 11:06:14 -0800 Subject: Fix a deadlock and some more work on RethinkDB (for central) integration. --- controller/DB.hpp | 4 +- controller/EmbeddedNetworkController.cpp | 31 +++---------- controller/FileDB.cpp | 7 ++- controller/FileDB.hpp | 4 +- controller/RethinkDB.cpp | 74 ++++++++++++++++++++++++++++++-- controller/RethinkDB.hpp | 10 ++++- node/Peer.cpp | 59 ++++--------------------- 7 files changed, 106 insertions(+), 83 deletions(-) (limited to 'node/Peer.cpp') diff --git a/controller/DB.hpp b/controller/DB.hpp index dfc8ac95..fe06c24d 100644 --- a/controller/DB.hpp +++ b/controller/DB.hpp @@ -78,12 +78,14 @@ public: void networks(std::vector &networks); - virtual void save(const nlohmann::json &record) = 0; + virtual void save(nlohmann::json *orig,nlohmann::json &record) = 0; virtual void eraseNetwork(const uint64_t networkId) = 0; virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0; + virtual void nodeIsOnline(const uint64_t memberId) = 0; + protected: struct _Network { diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 5707e6e0..a2795d96 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -734,12 +734,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( member["nwid"] = nwids; _removeMemberNonPersistedFields(member); - if (member != origMember) { - json &revj = member["revision"]; - member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - _db->save(member); - } - + _db->save(&origMember,member); _addMemberNonPersistedFields(nwid,address,member,now); responseBody = OSUtils::jsonDump(member); responseContentType = "application/json"; @@ -986,12 +981,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( network["nwid"] = nwids; // legacy _removeNetworkNonPersistedFields(network); - if (network != origNetwork) { - json &revj = network["revision"]; - network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - _db->save(network); - } - + _db->save(&origNetwork,network); ControllerDB::NetworkSummaryInfo ns; _db->summary(nwid,ns); _addNetworkNonPersistedFields(nwid,network,now,ns); @@ -1116,7 +1106,7 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) d["objtype"] = "trace"; d["ts"] = now; d["nodeId"] = Utils::hex10(rt.origin,tmp); - _db->save(d); + _db->save((nlohmann::json *)0,d); } catch ( ... ) { // drop invalid trace messages if an error occurs } @@ -1185,6 +1175,8 @@ void EmbeddedNetworkController::_request( ms.lastRequestTime = now; } + _db->nodeIsOnline(identity.address().toInt()); + Utils::hex(nwid,nwids); _db->get(nwid,network,identity.address().toInt(),member,ns); if ((!network.is_object())||(network.size() == 0)) { @@ -1299,11 +1291,7 @@ void EmbeddedNetworkController::_request( } else { // If they are not authorized, STOP! _removeMemberNonPersistedFields(member); - if (origMember != member) { - json &revj = member["revision"]; - member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - _db->save(member); - } + _db->save(&origMember,member); _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } @@ -1666,12 +1654,7 @@ void EmbeddedNetworkController::_request( } _removeMemberNonPersistedFields(member); - if (member != origMember) { - json &revj = member["revision"]; - member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); - _db->save(member); - } - + _db->save(&origMember,member); _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } diff --git a/controller/FileDB.cpp b/controller/FileDB.cpp index b48d5e87..646fa2fe 100644 --- a/controller/FileDB.cpp +++ b/controller/FileDB.cpp @@ -69,7 +69,7 @@ bool FileDB::waitForReady() return true; } -void FileDB::save(const nlohmann::json &record) +void FileDB::save(nlohmann::json *orig,nlohmann::json &record) { char p1[16384],p2[16384]; try { @@ -126,4 +126,9 @@ void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId) { } +void FileDB::nodeIsOnline(const uint64_t memberId) +{ + // Nothing to do here right now in the filesystem store mode since we can just get this from the peer list +} + } // namespace ZeroTier diff --git a/controller/FileDB.hpp b/controller/FileDB.hpp index fe9869b9..76a47936 100644 --- a/controller/FileDB.hpp +++ b/controller/FileDB.hpp @@ -32,12 +32,14 @@ public: virtual bool waitForReady(); - virtual void save(const nlohmann::json &record); + virtual void save(nlohmann::json *orig,nlohmann::json &record); virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); + virtual void nodeIsOnline(const uint64_t memberId); + protected: std::string _networksPath; }; diff --git a/controller/RethinkDB.cpp b/controller/RethinkDB.cpp index d1012167..031bd516 100644 --- a/controller/RethinkDB.cpp +++ b/controller/RethinkDB.cpp @@ -215,6 +215,47 @@ RethinkDB::RethinkDB(EmbeddedNetworkController *const nc,const Address &myAddres }); } + _onlineNotificationThread = std::thread([this]() { + try { + std::unique_ptr rdb; + while (_run == 1) { + try { + if (!rdb) + rdb = R::connect(this->_host,this->_port,this->_auth); + if (rdb) { + std::lock_guard l(_lastOnline_l); + R::Array batch; + R::Object tmpobj; + for(auto i=_lastOnline.begin();i!=_lastOnline.end();++i) { + char nodeId[16]; + Utils::hex10(i->first,nodeId); + tmpobj["id"] = nodeId; + tmpobj["ts"] = i->second; + batch.emplace_back(tmpobj); + if (batch.size() >= 256) { + R::db(this->_db).table("NodeLastOnline").insert(R::args(batch),R::optargs("conflict","update")).run(*rdb); + batch.clear(); + } + } + if (batch.size() > 0) + R::db(this->_db).table("NodeLastOnline").insert(R::args(batch),R::optargs("conflict","update")).run(*rdb); + _lastOnline.clear(); + } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: controller RethinkDB (node status update): %s" ZT_EOL_S,e.what()); + rdb.reset(); + } catch (R::Error &e) { + fprintf(stderr,"ERROR: controller RethinkDB (node status update): %s" ZT_EOL_S,e.message.c_str()); + rdb.reset(); + } catch ( ... ) { + fprintf(stderr,"ERROR: controller RethinkDB (node status update): unknown exception" ZT_EOL_S); + rdb.reset(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + } catch ( ... ) {} + }); + _heartbeatThread = std::thread([this]() { try { char tmp[1024]; @@ -251,9 +292,10 @@ RethinkDB::~RethinkDB() _membersDbWatcher.join(); _networksDbWatcher.join(); _heartbeatThread.join(); + _onlineNotificationThread.join(); } -void RethinkDB::waitForReady() +bool RethinkDB::waitForReady() { while (_ready > 0) { if (!_waitNoticePrinted) { @@ -263,12 +305,32 @@ void RethinkDB::waitForReady() _readyLock.lock(); _readyLock.unlock(); } + return true; } -void RethinkDB::save(const nlohmann::json &record) +void RethinkDB::save(nlohmann::json *orig,nlohmann::json &record) { + if (!record.is_object()) // sanity check + return; waitForReady(); - _commitQueue.post(new nlohmann::json(record)); + if (orig) { + if (*orig != record) { + nlohmann::json *q = new nlohmann::json(); + try { + record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1; + for(auto kv=record.begin();kv!=record.end();++kv) { + if ((kv.key() == "id")||(kv.key() == "nwid")||(kv.key() == "objtype")||((*q)[kv.key()] != kv.value())) + (*q)[kv.key()] = kv.value(); + } + } catch ( ... ) { + delete q; + throw; + } + } + } else { + record["revision"] = 1; + _commitQueue.post(new nlohmann::json(record)); + } } void RethinkDB::eraseNetwork(const uint64_t networkId) @@ -295,6 +357,12 @@ void RethinkDB::eraseMember(const uint64_t networkId,const uint64_t memberId) _commitQueue.post(tmp); } +void RethinkDB::nodeIsOnline(const uint64_t memberId) +{ + std::lock_guard l(_lastOnline_l); + _lastOnline[memberId] = OSUtils::now(); +} + } // namespace ZeroTier #endif // ZT_CONTROLLER_USE_RETHINKDB diff --git a/controller/RethinkDB.hpp b/controller/RethinkDB.hpp index 2309a25c..8c8b16a6 100644 --- a/controller/RethinkDB.hpp +++ b/controller/RethinkDB.hpp @@ -34,14 +34,16 @@ public: RethinkDB(EmbeddedNetworkController *const nc,const Address &myAddress,const char *path); virtual ~RethinkDB(); - virtual void waitForReady(); + virtual bool waitForReady(); - virtual void save(const nlohmann::json &record); + virtual void save(nlohmann::json *orig,nlohmann::json &record); virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); + virtual void nodeIsOnline(const uint64_t memberId); + protected: std::string _host; std::string _db; @@ -56,6 +58,10 @@ protected: BlockingQueue< nlohmann::json * > _commitQueue; std::thread _commitThread[ZT_CONTROLLER_RETHINKDB_COMMIT_THREADS]; + std::unordered_map< uint64_t,int64_t > _lastOnline; + mutable std::mutex _lastOnline_l; + std::thread _onlineNotificationThread; + std::thread _heartbeatThread; mutable std::mutex _readyLock; // locked until ready diff --git a/node/Peer.cpp b/node/Peer.cpp index a3682a97..2d562f12 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -78,54 +78,6 @@ void Peer::received( { const int64_t now = RR->node->now(); -/* -#ifdef ZT_ENABLE_CLUSTER - bool isClusterSuboptimalPath = false; - if ((RR->cluster)&&(hops == 0)) { - // Note: findBetterEndpoint() is first since we still want to check - // for a better endpoint even if we don't actually send a redirect. - InetAddress redirectTo; - if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),path->address(),false)) ) { - if (_vProto >= 5) { - // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS. - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp.append((uint16_t)1); // count == 1 - outp.append((uint8_t)ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT); // flags: cluster redirect - outp.append((uint16_t)0); // no extensions - if (redirectTo.ss_family == AF_INET) { - outp.append((uint8_t)4); - outp.append((uint8_t)6); - outp.append(redirectTo.rawIpData(),4); - } else { - outp.append((uint8_t)6); - outp.append((uint8_t)18); - outp.append(redirectTo.rawIpData(),16); - } - outp.append((uint16_t)redirectTo.port()); - outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,tPtr,outp.data(),outp.size(),now); - } else { - // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere. - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); // no flags - RR->identity.address().appendTo(outp); - outp.append((uint16_t)redirectTo.port()); - if (redirectTo.ss_family == AF_INET) { - outp.append((uint8_t)4); - outp.append(redirectTo.rawIpData(),4); - } else { - outp.append((uint8_t)16); - outp.append(redirectTo.rawIpData(),16); - } - outp.armor(_key,true,path->nextOutgoingCounter()); - path->send(RR,tPtr,outp.data(),outp.size(),now); - } - isClusterSuboptimalPath = true; - } - } -#endif -*/ - _lastReceive = now; switch (verb) { case Packet::VERB_FRAME: @@ -163,6 +115,7 @@ void Peer::received( } } + bool attemptToContact = false; if ((!havePath)&&(RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()))) { Mutex::Lock _l(_paths_m); @@ -201,13 +154,17 @@ void Peer::received( _paths[replacePath].p = path; _paths[replacePath].priority = 1; } else { - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); - path->sent(now); - RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); + attemptToContact = true; } } } } + + if (attemptToContact) { + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + path->sent(now); + RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); + } } // If we have a trust relationship periodically push a message enumerating -- cgit v1.2.3 From 16613ab5fb5a1f6cb1271ae67e68836a1898023d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 4 Dec 2017 14:40:10 -0800 Subject: Clean up remote tracing code, add per-network remote trace settings, add remote trace level, and make local trace output readable again. --- include/ZeroTierOne.h | 23 +- node/Hashtable.hpp | 18 ++ node/MAC.hpp | 23 ++ node/NetworkConfig.cpp | 2 + node/NetworkConfig.hpp | 10 +- node/Node.cpp | 8 +- node/Node.hpp | 4 + node/Peer.cpp | 2 +- node/Switch.cpp | 1 - node/Trace.cpp | 594 +++++++++++++++++++++++++++++++------------------ node/Trace.hpp | 37 ++- 11 files changed, 474 insertions(+), 248 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 16668534..04c4b83b 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -293,7 +293,6 @@ extern "C" { #define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId" #define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "packetTrustedPathApproved" #define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops" -#define ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR "oldRemotePhyAddr" #define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr" #define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr" #define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr" @@ -326,12 +325,11 @@ extern "C" { // Event types in remote traces #define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 -#define ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT 0x1001 -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1002 -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1003 -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1004 -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1005 -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1006 +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001 +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002 +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003 +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004 +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005 #define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006 #define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED 0x2000 #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED 0x2001 @@ -343,12 +341,11 @@ extern "C" { // Event types in remote traces in hex string form #define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" -#define ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT_S "1001" -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1002" -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1003" -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1004" -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1005" -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1006" +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001" +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002" +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003" +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004" +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005" #define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" #define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index e5496592..5aa045b9 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -255,6 +255,24 @@ public: } inline const V *get(const K &k) const { return const_cast(this)->get(k); } + /** + * @param k Key + * @param v Value to fill with result + * @return True if value was found and set (if false, v is not modified) + */ + inline bool get(const K &k,V &v) const + { + _Bucket *b = _t[_hc(k) % _bc]; + while (b) { + if (b->k == k) { + v = b->v; + return true; + } + b = b->next; + } + return false; + } + /** * @param k Key to check * @return True if key is present diff --git a/node/MAC.hpp b/node/MAC.hpp index a179fd4f..18fe2032 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -200,6 +200,29 @@ public: inline unsigned long hashCode() const { return (unsigned long)_m; } + inline char *toString(char buf[18]) const + { + buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf]; + buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf]; + buf[2] = ':'; + buf[3] = Utils::HEXCHARS[(_m >> 36) & 0xf]; + buf[4] = Utils::HEXCHARS[(_m >> 32) & 0xf]; + buf[5] = ':'; + buf[6] = Utils::HEXCHARS[(_m >> 28) & 0xf]; + buf[7] = Utils::HEXCHARS[(_m >> 24) & 0xf]; + buf[8] = ':'; + buf[9] = Utils::HEXCHARS[(_m >> 20) & 0xf]; + buf[10] = Utils::HEXCHARS[(_m >> 16) & 0xf]; + buf[11] = ':'; + buf[12] = Utils::HEXCHARS[(_m >> 12) & 0xf]; + buf[13] = Utils::HEXCHARS[(_m >> 8) & 0xf]; + buf[14] = ':'; + buf[15] = Utils::HEXCHARS[(_m >> 4) & 0xf]; + buf[16] = Utils::HEXCHARS[_m & 0xf]; + buf[17] = (char)0; + return buf; + } + inline MAC &operator=(const MAC &m) { _m = m._m; diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 110a20b0..2e07ac82 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -49,6 +49,7 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; @@ -220,6 +221,7 @@ bool NetworkConfig::fromDictionary(const DictionaryremoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET); + this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL); this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 1bd3b9aa..bb48e6aa 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -49,6 +49,7 @@ #include "Dictionary.hpp" #include "Identity.hpp" #include "Utils.hpp" +#include "Trace.hpp" /** * Default maximum time delta for COMs, tags, and capabilities @@ -161,6 +162,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id" // remote trace target #define ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET "tt" +// remote trace level +#define ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL "tl" // flags(hex) #define ZT_NETWORKCONFIG_DICT_KEY_FLAGS "f" // integer(hex) @@ -189,8 +192,6 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_TAGS "TAG" // tags (binary blobs) #define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP "COO" -// curve25519 signature -#define ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE "C25519" // Legacy fields -- these are obsoleted but are included when older clients query @@ -445,6 +446,11 @@ public: */ uint64_t flags; + /** + * Remote trace level + */ + Trace::Level remoteTraceLevel; + /** * Network MTU */ diff --git a/node/Node.cpp b/node/Node.cpp index f0fcb4d7..ef8925d5 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -61,7 +61,8 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64 _networks(8), _now(now), _lastPingCheck(0), - _lastHousekeepingRun(0) + _lastHousekeepingRun(0), + _lastMemoizedTraceSettings(0) { if (callbacks->version != 0) throw ZT_EXCEPTION_INVALID_ARGUMENT; @@ -299,6 +300,11 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 timeUntilNextPingCheck -= (unsigned long)timeSinceLastPingCheck; } + if ((now - _lastMemoizedTraceSettings) >= 10000) { + _lastMemoizedTraceSettings = now; + RR->t->updateMemoizedSettings(); + } + if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { _lastHousekeepingRun = now; try { diff --git a/node/Node.hpp b/node/Node.hpp index ae7976d4..f8236db8 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -258,6 +258,7 @@ public: virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; } + inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; } private: RuntimeEnvironment _RR; @@ -281,9 +282,12 @@ private: Mutex _backgroundTasksLock; Address _remoteTraceTarget; + enum Trace::Level _remoteTraceLevel; + int64_t _now; int64_t _lastPingCheck; int64_t _lastHousekeepingRun; + int64_t _lastMemoizedTraceSettings; volatile int64_t _prngState[2]; bool _online; }; diff --git a/node/Peer.cpp b/node/Peer.cpp index 2d562f12..fceef94f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -149,7 +149,7 @@ void Peer::received( if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) { if (verb == Packet::VERB_OK) { - RR->t->peerLearnedNewPath(tPtr,networkId,*this,_paths[replacePath].p,path,packetId); + RR->t->peerLearnedNewPath(tPtr,networkId,*this,path,packetId); _paths[replacePath].lr = now; _paths[replacePath].p = path; _paths[replacePath].priority = 1; diff --git a/node/Switch.cpp b/node/Switch.cpp index a8cf0ce6..1958c43e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -579,7 +579,6 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now) if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); } else { if (!RR->topology->getPeer(tPtr,txi->dest)) diff --git a/node/Trace.cpp b/node/Trace.cpp index 6d85942d..7ffe0c8f 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -24,6 +24,10 @@ * of your own application. */ +#define ZT_TRACE + +#include + #include "Trace.hpp" #include "RuntimeEnvironment.hpp" #include "Switch.hpp" @@ -38,180 +42,292 @@ namespace ZeroTier { +#ifdef ZT_TRACE +static void ZT_LOCAL_TRACE(void *const tPtr,const RuntimeEnvironment *const RR,const char *const fmt,...) +{ + char traceMsgBuf[1024]; + va_list ap; + va_start(ap,fmt); + vsnprintf(traceMsgBuf,sizeof(traceMsgBuf),fmt,ap); + va_end(ap); + traceMsgBuf[sizeof(traceMsgBuf) - 1] = (char)0; + RR->node->postEvent(tPtr,ZT_EVENT_TRACE,traceMsgBuf); +} +#else +#define ZT_LOCAL_TRACE(...) +#endif + void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) { char tmp[128]; + + ZT_LOCAL_TRACE(tPtr,RR,"RESET and revalidate paths in scope %d; new phy address %s reported by trusted peer %.10llx",(int)scope,myPhysicalAddress.toIpString(tmp),reporter.toInt()); + Dictionary d; d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,reporter); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,reporterPhysicalAddress.toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope); - _send(tPtr,d,0); -} -void Trace::txTimedOut(void *const tPtr,const Address &destination) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__TX_TIMED_OUT_S); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,destination); - _send(tPtr,d,0); + if (_globalTarget) + _send(tPtr,d,_globalTarget); + _spamToAllNetworks(tPtr,d,Trace::NORMAL); } void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) { char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (!path) return; // sanity check + + ZT_LOCAL_TRACE(tPtr,RR,"trying unknown path %s to %.10llx (packet %.16llx verb %d local socket %lld network %.16llx)",path->address().toString(tmp),peer.address().toInt(),packetId,(double)verb,path->localSocket(),networkId); + + std::pair byn; + if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + if (networkId) + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); } - _send(tPtr,d,networkId); } -void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId) +void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath,const uint64_t packetId) { char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - if (oldPath) { - d.add(ZT_REMOTE_TRACE_FIELD__OLD_REMOTE_PHYADDR,oldPath->address().toString(tmp)); - } - if (newPath) { + if (!newPath) return; // sanity check + + ZT_LOCAL_TRACE(tPtr,RR,"learned new path %s to %.10llx (packet %.16llx local socket %lld network %.16llx)",newPath->address().toString(tmp),peer.address().toInt(),packetId,newPath->localSocket(),networkId); + + std::pair byn; + if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + if (networkId) + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); } - _send(tPtr,d,networkId); } void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath) { char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - if (newPath) { + if (!newPath) return; // sanity check + + ZT_LOCAL_TRACE(tPtr,RR,"explicit redirect from %.10llx to path %s",peer.address().toInt(),newPath->address().toString(tmp)); + + std::pair byn; + if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); + if (networkId) + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); } - _send(tPtr,d,networkId); } void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) { + char tmp[128],tmp2[128]; if (!network) return; // sanity check - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); - d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); - d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROP frame %s -> %s etherType %.4x size %u (%s)",network->id(),sourceMac.toString(tmp),destMac.toString(tmp2),etherType,frameLen,(reason) ? reason : "unknown reason"); + + std::pair byn; + { Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } + + if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::VERBOSE)) ) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::VERBOSE)) + _send(tPtr,d,_globalTarget); + if ((byn.first)&&((int)byn.second >= (int)Trace::VERBOSE)) + _send(tPtr,d,byn.first); } - _send(tPtr,d,network); } void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) { - if (!network) return; // sanity check char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (!network) return; // sanity check + + ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DENIED packet from %.10llx(%s) verb %d size %u%s",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength,credentialsRequested ? " (credentials requested)" : " (credentials not requested)"); + + std::pair byn; + { Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } + + if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::VERBOSE)) ) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + + if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::VERBOSE)) + _send(tPtr,d,_globalTarget); + if ((byn.first)&&((int)byn.second >= (int)Trace::VERBOSE)) + _send(tPtr,d,byn.first); } - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); - _send(tPtr,d,*network); } void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason) { - if (!network) return; // sanity check char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (!network) return; // sanity check + + ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROPPED frame from %.10llx(%s) verb %d size %u",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength); + + std::pair byn; + { Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } + + if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::VERBOSE)) ) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::VERBOSE)) + _send(tPtr,d,_globalTarget); + if ((byn.first)&&((int)byn.second >= (int)Trace::VERBOSE)) + _send(tPtr,d,byn.first); } - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,*network); } void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) { char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + + ZT_LOCAL_TRACE(tPtr,RR,"MAC failed for packet %.16llx from %.10llx(%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???"); + + if ((_globalTarget)&&((int)_globalLevel >= Trace::DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + _send(tPtr,d,_globalTarget); + } } void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason) { char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + + ZT_LOCAL_TRACE(tPtr,RR,"INVALID packet %.16llx from %.10llx(%s) (%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "unknown reason"); + + if ((_globalTarget)&&((int)_globalLevel >= Trace::DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + _send(tPtr,d,_globalTarget); + } } void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) { char tmp[128]; - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,0); + + ZT_LOCAL_TRACE(tPtr,RR,"DROPPED HELLO from %.10llx(%s) (%s)",source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "???"); + + if ((_globalTarget)&&((int)_globalLevel >= Trace::DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + } + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + _send(tPtr,d,_globalTarget); + } } void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller); - _send(tPtr,d,network); + ZT_LOCAL_TRACE(tPtr,RR,"requesting configuration for network %.16llx",network.id()); + if ((_globalTarget)&&((int)_globalLevel >= Trace::DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller); + _send(tPtr,d,_globalTarget); + } } void Trace::networkFilter( @@ -232,153 +348,189 @@ void Trace::networkFilter( const bool inbound, const int accept) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR,ztSource); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR,ztDest); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,macSource.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,macDest.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); - d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE,noTee ? "1" : "0"); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND,inbound ? "1" : "0"); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT,(int64_t)accept); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG,(const char *)primaryRuleSetLog.data(),(int)primaryRuleSetLog.sizeBytes()); - if (matchingCapabilityRuleSetLog) - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG,(const char *)matchingCapabilityRuleSetLog->data(),(int)matchingCapabilityRuleSetLog->sizeBytes()); - if (matchingCapability) - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID,(uint64_t)matchingCapability->id()); - d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); - if (frameLen > 0) - d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen); - _send(tPtr,d,network); + std::pair byn; + { Mutex::Lock l(_byNet_m); _byNet.get(network.id(),byn); } + + if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::RULES)) || ((byn.first)&&((int)byn.second >= (int)Trace::RULES)) ) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR,ztSource); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR,ztDest); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,macSource.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,macDest.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE,noTee ? "1" : "0"); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND,inbound ? "1" : "0"); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT,(int64_t)accept); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG,(const char *)primaryRuleSetLog.data(),(int)primaryRuleSetLog.sizeBytes()); + if (matchingCapabilityRuleSetLog) + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG,(const char *)matchingCapabilityRuleSetLog->data(),(int)matchingCapabilityRuleSetLog->sizeBytes()); + if (matchingCapability) + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID,(uint64_t)matchingCapability->id()); + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); + if (frameLen > 0) + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen); + + if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::RULES)) + _send(tPtr,d,_globalTarget); + if ((byn.first)&&((int)byn.second >= (int)Trace::RULES)) + _send(tPtr,d,byn.first); + } } void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,c.networkId()); + std::pair byn; + if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); + } } void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,c.networkId()); + std::pair byn; + if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); + } } void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,c.networkId()); + std::pair byn; + if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); + } } void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,c.networkId()); + std::pair byn; + if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); + } } void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); - if (reason) - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - _send(tPtr,d,c.networkId()); + std::pair byn; + if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); } + + if ((_globalTarget)||(byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); + + if (_globalTarget) + _send(tPtr,d,_globalTarget); + if (byn.first) + _send(tPtr,d,byn.first); + } } -void Trace::_send(void *const tPtr,const Dictionary &d) +void Trace::updateMemoizedSettings() { -#ifdef ZT_TRACE - unsigned int i = 0; - while (i < (unsigned int)(sizeof(_traceMsgBuf) - 1)) { - const char c = d.data()[i]; - if (c == 0) { - break; - } else if (c == '\n') { - _traceMsgBuf[i++] = ' '; - } else if ((c >= 32)&&(c <= 126)) { - _traceMsgBuf[i++] = c; - } else { - if ((i + 3) < (unsigned int)(sizeof(_traceMsgBuf) - 1)) { - _traceMsgBuf[i++] = '\\'; - Utils::hex((uint8_t)c,_traceMsgBuf + i); + _globalTarget = RR->node->remoteTraceTarget(); + _globalLevel = RR->node->remoteTraceLevel(); + const std::vector< SharedPtr > nws(RR->node->allNetworks()); + { + Mutex::Lock l(_byNet_m); + _byNet.clear(); + for(std::vector< SharedPtr >::const_iterator n(nws.begin());n!=nws.end();++n) { + const Address dest((*n)->config().remoteTraceTarget); + if (dest) { + std::pair &m = _byNet[(*n)->id()]; + m.first = dest; + m.second = (*n)->config().remoteTraceLevel; } } } - _traceMsgBuf[i] = (char)0; - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,_traceMsgBuf); -#endif - - const Address rtt(RR->node->remoteTraceTarget()); - if (rtt) { - Packet outp(rtt,RR->identity.address(),Packet::VERB_REMOTE_TRACE); - outp.appendCString(d.data()); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } } -void Trace::_send(void *const tPtr,const Dictionary &d,const uint64_t networkId) +void Trace::_send(void *const tPtr,const Dictionary &d,const Address &dest) { - _send(tPtr,d); - if (networkId) { - const SharedPtr network(RR->node->network(networkId)); - if ((network)&&(network->config().remoteTraceTarget)) { - Packet outp(network->config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); - outp.appendCString(d.data()); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } - } + Packet outp(dest,RR->identity.address(),Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr,outp,true); } -void Trace::_send(void *const tPtr,const Dictionary &d,const Network &network) +void Trace::_spamToAllNetworks(void *const tPtr,const Dictionary &d,const Level level) { - _send(tPtr,d); - if (network.config().remoteTraceTarget) { - Packet outp(network.config().remoteTraceTarget,RR->identity.address(),Packet::VERB_REMOTE_TRACE); - outp.appendCString(d.data()); - outp.compress(); - RR->sw->send(tPtr,outp,true); + Mutex::Lock l(_byNet_m); + Hashtable< uint64_t,std::pair< Address,Trace::Level > >::Iterator i(_byNet); + uint64_t *k = (uint64_t *)0; + std::pair *v = (std::pair *)0; + while (i.next(k,v)) { + if ((v)&&(v->first)&&((int)v->second >= (int)level)) + _send(tPtr,d,v->first); } } diff --git a/node/Trace.hpp b/node/Trace.hpp index 4192d1c2..08241d37 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -40,6 +40,8 @@ #include "Credential.hpp" #include "InetAddress.hpp" #include "Dictionary.hpp" +#include "Mutex.hpp" +#include "Hashtable.hpp" namespace ZeroTier { @@ -63,6 +65,18 @@ class Capability; class Trace { public: + /** + * Trace verbosity level + */ + enum Level + { + NORMAL = 0, + VERBOSE = 10, + RULES = 15, + DEBUG = 20, + INSANE = 30 + }; + /** * Filter rule evaluation result log * @@ -98,13 +112,16 @@ public: uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; }; - Trace(const RuntimeEnvironment *renv) : RR(renv) {} + Trace(const RuntimeEnvironment *renv) : + RR(renv), + _byNet(8) + { + } void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); - void txTimedOut(void *const tPtr,const Address &destination); void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); - void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); + void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath,const uint64_t packetId); void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath); void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); @@ -140,16 +157,18 @@ public: void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); + void updateMemoizedSettings(); + private: const RuntimeEnvironment *const RR; - void _send(void *const tPtr,const Dictionary &d); - void _send(void *const tPtr,const Dictionary &d,const uint64_t networkId); - void _send(void *const tPtr,const Dictionary &d,const Network &network); + void _send(void *const tPtr,const Dictionary &d,const Address &dest); + void _spamToAllNetworks(void *const tPtr,const Dictionary &d,const Level level); -#ifdef ZT_TRACE - char _traceMsgBuf[4096]; -#endif + Address _globalTarget; + Trace::Level _globalLevel; + Hashtable< uint64_t,std::pair< Address,Trace::Level > > _byNet; + Mutex _byNet_m; }; } // namespace ZeroTier -- cgit v1.2.3 From 9c7ee5a21e2875baf3b1643101f660f41c903124 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 Jan 2018 13:06:24 -0800 Subject: Tear out old "link quality" stuff since it is not currently used and will be done differently. --- include/ZeroTierOne.h | 5 ----- node/IncomingPacket.cpp | 26 ++++++++++----------- node/Node.cpp | 7 +++--- node/Packet.cpp | 6 ++--- node/Packet.hpp | 9 +------- node/Path.hpp | 60 ------------------------------------------------- node/Peer.cpp | 29 +++++++++++------------- node/Peer.hpp | 8 +++---- node/Switch.cpp | 4 ++-- one.cpp | 3 +-- service/OneService.cpp | 1 - 11 files changed, 38 insertions(+), 120 deletions(-) (limited to 'node/Peer.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 04c4b83b..93a91933 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1183,11 +1183,6 @@ typedef struct */ uint64_t trustedPathId; - /** - * Path link quality from 0 to 255 (always 255 if peer does not support) - */ - int linkQuality; - /** * Is path expired? */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index d44e3b54..38fd3aa0 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -241,7 +241,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.append((uint8_t)Packet::VERB_HELLO); outp.append((uint64_t)pid); outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true,_path->nextOutgoingCounter()); + outp.armor(key,true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); @@ -391,7 +391,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool } outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -538,7 +538,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar } if (count > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -560,7 +560,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { const uint64_t junk = RR->node->prng(); RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false,0); + rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false); } } } @@ -669,7 +669,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const outp.append((uint8_t)Packet::VERB_EXT_FRAME); outp.append((uint64_t)packetId()); outp.append((uint64_t)nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -692,7 +692,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share outp.append((uint64_t)pid); if (size() > ZT_PACKET_IDX_PAYLOAD) outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); peer->received(tPtr,_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0); @@ -885,7 +885,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void outp.append(requestPacketId); outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -905,7 +905,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c outp.append((uint64_t)packetId()); outp.append((uint64_t)network->id()); outp.append((uint64_t)configUpdateId); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -948,7 +948,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr outp.append((uint32_t)mg.adi()); const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); if (gatheredLocally > 0) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1043,7 +1043,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, outp.append((uint32_t)to.adi()); outp.append((unsigned char)0x02); // flag 0x02 = contains gather results if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1094,7 +1094,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false); } } } break; @@ -1108,7 +1108,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { peer->clusterRedirect(tPtr,_path,a,now); } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); + peer->attemptToContactAt(tPtr,InetAddress(),a,now,false); } } } break; @@ -1170,7 +1170,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void outp.append(packetId()); outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); - outp.armor(peer->key(),true,_path->nextOutgoingCounter()); + outp.armor(peer->key(),true); _path->send(RR,tPtr,outp.data(),outp.size(),now); } } diff --git a/node/Node.cpp b/node/Node.cpp index 8d8f5ca0..d4b69689 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -202,7 +202,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET) { - p->sendHELLO(_tPtr,-1,addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now); contacted = true; break; } @@ -213,7 +213,7 @@ public: for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) { const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()]; if (addr.ss_family == AF_INET6) { - p->sendHELLO(_tPtr,-1,addr,_now,0); + p->sendHELLO(_tPtr,-1,addr,_now); contacted = true; break; } @@ -225,7 +225,7 @@ public: if ((!contacted)&&(_bestCurrentUpstream)) { const SharedPtr up(_bestCurrentUpstream->getBestPath(_now,true)); if (up) - p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now,up->nextOutgoingCounter()); + p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now); } lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); @@ -445,7 +445,6 @@ ZT_PeerList *Node::peers() const p->paths[p->pathCount].lastSend = (*path)->lastOut(); p->paths[p->pathCount].lastReceive = (*path)->lastIn(); p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); - p->paths[p->pathCount].linkQuality = (int)(*path)->linkQuality(); p->paths[p->pathCount].expired = 0; p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; ++p->pathCount; diff --git a/node/Packet.cpp b/node/Packet.cpp index af42cda5..cb9e1e0f 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1061,18 +1061,16 @@ static inline int LZ4_decompress_safe(const char* source, char* dest, int compre const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -void Packet::armor(const void *key,bool encryptPayload,unsigned int counter) +void Packet::armor(const void *key,bool encryptPayload) { uint8_t mangledKey[32]; uint8_t *const data = reinterpret_cast(unsafeData()); - // Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use - data[7] = (data[7] & 0xf8) | (uint8_t)(counter & 0x07); - // Set flag now, since it affects key mangle function setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); _salsa20MangleKey((const unsigned char *)key,mangledKey); + if (ZT_HAS_FAST_CRYPTO()) { const unsigned int encryptLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0; uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; diff --git a/node/Packet.hpp b/node/Packet.hpp index cc055347..8cfb5492 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -68,7 +68,6 @@ * + Tags and Capabilities * + Inline push of CertificateOfMembership deprecated * 9 - 1.2.0 ... CURRENT - * + In-band encoding of packet counter for link quality measurement */ #define ZT_PROTO_VERSION 9 @@ -1202,11 +1201,6 @@ public: */ inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } - /** - * @return Value of link quality counter extracted from this packet's ID, range 0 to 7 (3 bits) - */ - inline unsigned int linkQualityCounter() const { return (unsigned int)(reinterpret_cast(data())[7] & 0x07); } - /** * Set packet verb * @@ -1237,9 +1231,8 @@ public: * * @param key 32-byte key * @param encryptPayload If true, encrypt packet payload, else just MAC - * @param counter Packet send counter for destination peer -- only least significant 3 bits are used */ - void armor(const void *key,bool encryptPayload,unsigned int counter); + void armor(const void *key,bool encryptPayload); /** * Verify and (if encrypted) decrypt packet diff --git a/node/Path.hpp b/node/Path.hpp index 008b05c5..6b4b9915 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -94,36 +94,22 @@ public: _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), - _incomingLinkQualityFastLog(0xffffffffffffffffULL), _localSocket(-1), - _incomingLinkQualitySlowLogPtr(0), - _incomingLinkQualitySlowLogCounter(-64), // discard first fast log - _incomingLinkQualityPreviousPacketCounter(0), - _outgoingPacketCounter(0), _latency(0xffff), _addr(), _ipScope(InetAddress::IP_SCOPE_NONE) { - for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) - _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } Path(const int64_t localSocket,const InetAddress &addr) : _lastOut(0), _lastIn(0), _lastTrustEstablishedPacketReceived(0), - _incomingLinkQualityFastLog(0xffffffffffffffffULL), _localSocket(localSocket), - _incomingLinkQualitySlowLogPtr(0), - _incomingLinkQualitySlowLogCounter(-64), // discard first fast log - _incomingLinkQualityPreviousPacketCounter(0), - _outgoingPacketCounter(0), _latency(0xffff), _addr(addr), _ipScope(addr.ipScope()) { - for(int i=0;i<(int)sizeof(_incomingLinkQualitySlowLog);++i) - _incomingLinkQualitySlowLog[i] = ZT_PATH_LINK_QUALITY_MAX; } /** @@ -133,39 +119,6 @@ public: */ inline void received(const uint64_t t) { _lastIn = t; } - /** - * Update link quality using a counter from an incoming packet (or packet head in fragmented case) - * - * @param counter Packet link quality counter (range 0 to 7, must not have other bits set) - */ - inline void updateLinkQuality(const unsigned int counter) - { - const unsigned int prev = _incomingLinkQualityPreviousPacketCounter; - _incomingLinkQualityPreviousPacketCounter = counter; - const uint64_t fl = (_incomingLinkQualityFastLog = ((_incomingLinkQualityFastLog << 1) | (uint64_t)(prev == ((counter - 1) & 0x7)))); - if (++_incomingLinkQualitySlowLogCounter >= 64) { - _incomingLinkQualitySlowLogCounter = 0; - _incomingLinkQualitySlowLog[_incomingLinkQualitySlowLogPtr++ % sizeof(_incomingLinkQualitySlowLog)] = (uint8_t)Utils::countBits(fl); - } - } - - /** - * @return Link quality from 0 (min) to 255 (max) - */ - inline unsigned int linkQuality() const - { - unsigned long slsize = _incomingLinkQualitySlowLogPtr; - if (slsize > (unsigned long)sizeof(_incomingLinkQualitySlowLog)) - slsize = (unsigned long)sizeof(_incomingLinkQualitySlowLog); - else if (!slsize) - return 255; // ZT_PATH_LINK_QUALITY_MAX - unsigned long lq = 0; - for(unsigned long i=0;i= 255) ? 255 : lq); - } - /** * Set time last trusted packet was received (done in Peer::received()) */ @@ -313,27 +266,14 @@ public: */ inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } - /** - * Return and increment outgoing packet counter (used with Packet::armor()) - * - * @return Next value that should be used for outgoing packet counter (only least significant 3 bits are used) - */ - inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; } - private: volatile int64_t _lastOut; volatile int64_t _lastIn; volatile int64_t _lastTrustEstablishedPacketReceived; - volatile uint64_t _incomingLinkQualityFastLog; int64_t _localSocket; - volatile unsigned long _incomingLinkQualitySlowLogPtr; - volatile signed int _incomingLinkQualitySlowLogCounter; - volatile unsigned int _incomingLinkQualityPreviousPacketCounter; - volatile unsigned int _outgoingPacketCounter; volatile unsigned int _latency; InetAddress _addr; InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often - volatile uint8_t _incomingLinkQualitySlowLog[32]; AtomicCounter __refCount; }; diff --git a/node/Peer.cpp b/node/Peer.cpp index fceef94f..6e46089f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -95,9 +95,6 @@ void Peer::received( path->trustedPacketReceived(now); } - if (_vProto >= 9) - path->updateLinkQuality((unsigned int)(packetId & 7)); - if (hops == 0) { // If this is a direct packet (no hops), update existing paths or learn new ones @@ -161,7 +158,7 @@ void Peer::received( } if (attemptToContact) { - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true,path->nextOutgoingCounter()); + attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true); path->sent(now); RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); } @@ -226,7 +223,7 @@ void Peer::received( if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp.armor(_key,true,path->nextOutgoingCounter()); + outp.armor(_key,true); path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -357,7 +354,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o outp.append((uint8_t)4); outp.append(other->_paths[theirs].p->address().rawIpData(),4); } - outp.armor(_key,true,_paths[mine].p->nextOutgoingCounter()); + outp.armor(_key,true); _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); } else { Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -371,7 +368,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o outp.append((uint8_t)4); outp.append(_paths[mine].p->address().rawIpData(),4); } - outp.armor(other->_key,true,other->_paths[theirs].p->nextOutgoingCounter()); + outp.armor(other->_key,true); other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); } ++alt; @@ -379,7 +376,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } } -void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter) +void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); @@ -415,22 +412,22 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA RR->node->expectReplyTo(outp.packetId()); if (atAddress) { - outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC + outp.armor(_key,false); // false == don't encrypt full payload, but add MAC RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } -void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter) +void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello) { if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); RR->node->expectReplyTo(outp.packetId()); - outp.armor(_key,true,counter); + outp.armor(_key,true); RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); } else { - sendHELLO(tPtr,localSocket,atAddress,now,counter); + sendHELLO(tPtr,localSocket,atAddress,now); } } @@ -440,7 +437,7 @@ void Peer::tryMemorizedPath(void *tPtr,int64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) - attemptToContactAt(tPtr,-1,mp,now,true,0); + attemptToContactAt(tPtr,-1,mp,now,true); } } @@ -470,7 +467,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) // Clean expired and reduced priority paths if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) { if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello,_paths[i].p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello); _paths[i].p->sent(now); sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; } @@ -495,7 +492,7 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr &originatingPath,con SharedPtr np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress)); RR->t->peerRedirected(tPtr,0,*this,np); - attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true,np->nextOutgoingCounter()); + attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true); { Mutex::Lock _l(_paths_m); @@ -545,7 +542,7 @@ void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddres for(unsigned int i=0;iaddress().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false,_paths[i].p->nextOutgoingCounter()); + attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false); _paths[i].p->sent(now); _paths[i].lr = 0; // path will not be used unless it speaks again } diff --git a/node/Peer.hpp b/node/Peer.hpp index 53b916ab..99728736 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -175,9 +175,8 @@ public: * @param localSocket Local source socket * @param atAddress Destination address * @param now Current time - * @param counter Outgoing packet counter */ - void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,unsigned int counter); + void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now); /** * Send ECHO (or HELLO for older peers) to this peer at the given address @@ -189,9 +188,8 @@ public: * @param atAddress Destination address * @param now Current time * @param sendFullHello If true, always send a full HELLO instead of just an ECHO - * @param counter Outgoing packet counter */ - void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello,unsigned int counter); + void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello); /** * Try a memorized or statically defined path if any are known @@ -480,7 +478,7 @@ public: try { ptr += inaddr.deserialize(b,ptr); if (inaddr) - p->attemptToContactAt(tPtr,-1,inaddr,now,true,0); + p->attemptToContactAt(tPtr,-1,inaddr,now,true); } catch ( ... ) { break; } diff --git a/node/Switch.cpp b/node/Switch.cpp index 1958c43e..b2cab1d0 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -78,7 +78,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses _lastBeaconResponse = now; Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),true,path->nextOutgoingCounter()); + outp.armor(peer->key(),true); path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -670,7 +670,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) if (trustedPathId) { packet.setTrusted(trustedPathId); } else { - packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter()); + packet.armor(peer->key(),encrypt); } if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { diff --git a/one.cpp b/one.cpp index 48b5d9a2..a1238bb8 100644 --- a/one.cpp +++ b/one.cpp @@ -365,8 +365,7 @@ static int cli(int argc,char **argv) char tmp[256]; std::string addr = path["address"]; const int64_t now = OSUtils::now(); - const double lq = (path.count("linkQuality")) ? (double)path["linkQuality"] : -1.0; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld;%1.2f",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"],lq); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s;%lld;%lld",addr.c_str(),now - (int64_t)path["lastSend"],now - (int64_t)path["lastReceive"]); bestPath = tmp; break; } diff --git a/service/OneService.cpp b/service/OneService.cpp index 3ca75362..686806b3 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -271,7 +271,6 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) j["lastSend"] = (lastSend < 0) ? 0 : lastSend; j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive; j["trustedPathId"] = peer->paths[i].trustedPathId; - j["linkQuality"] = (double)peer->paths[i].linkQuality / (double)ZT_PATH_LINK_QUALITY_MAX; j["active"] = (bool)(peer->paths[i].expired == 0); j["expired"] = (bool)(peer->paths[i].expired != 0); j["preferred"] = (bool)(peer->paths[i].preferred != 0); -- cgit v1.2.3 From 65c07afe055e6d33a07ea6adf87aedcf564806a2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 8 Jan 2018 14:33:28 -0800 Subject: Copyright updates for 2018. --- COPYING | 2 +- include/ZeroTierOne.h | 2 +- node/Address.hpp | 2 +- node/Array.hpp | 2 +- node/AtomicCounter.hpp | 2 +- node/Buffer.hpp | 2 +- node/C25519.hpp | 2 +- node/Capability.cpp | 2 +- node/Capability.hpp | 2 +- node/CertificateOfMembership.cpp | 2 +- node/CertificateOfMembership.hpp | 2 +- node/CertificateOfOwnership.cpp | 2 +- node/CertificateOfOwnership.hpp | 2 +- node/Constants.hpp | 2 +- node/Credential.hpp | 2 +- node/Dictionary.hpp | 2 +- node/Hashtable.hpp | 2 +- node/Identity.cpp | 2 +- node/Identity.hpp | 2 +- node/IncomingPacket.cpp | 2 +- node/IncomingPacket.hpp | 2 +- node/InetAddress.cpp | 2 +- node/InetAddress.hpp | 2 +- node/MAC.hpp | 2 +- node/Membership.cpp | 2 +- node/Membership.hpp | 2 +- node/MulticastGroup.hpp | 2 +- node/Multicaster.cpp | 2 +- node/Multicaster.hpp | 2 +- node/Mutex.hpp | 2 +- node/Network.cpp | 2 +- node/Network.hpp | 2 +- node/NetworkConfig.cpp | 2 +- node/NetworkConfig.hpp | 2 +- node/NetworkController.hpp | 2 +- node/Node.cpp | 2 +- node/Node.hpp | 2 +- node/NonCopyable.hpp | 2 +- node/OutboundMulticast.cpp | 2 +- node/OutboundMulticast.hpp | 2 +- node/Packet.cpp | 2 +- node/Packet.hpp | 2 +- node/Path.cpp | 2 +- node/Path.hpp | 2 +- node/Peer.cpp | 2 +- node/Peer.hpp | 2 +- node/Poly1305.hpp | 2 +- node/Revocation.cpp | 2 +- node/Revocation.hpp | 2 +- node/RuntimeEnvironment.hpp | 2 +- node/SHA512.hpp | 2 +- node/SelfAwareness.cpp | 2 +- node/SelfAwareness.hpp | 2 +- node/SharedPtr.hpp | 2 +- node/Switch.cpp | 2 +- node/Switch.hpp | 2 +- node/Tag.cpp | 2 +- node/Tag.hpp | 2 +- node/Topology.cpp | 2 +- node/Topology.hpp | 2 +- node/Trace.cpp | 2 +- node/Trace.hpp | 2 +- node/Utils.cpp | 2 +- node/Utils.hpp | 2 +- node/World.hpp | 2 +- one.cpp | 4 ++-- osdep/Arp.cpp | 2 +- osdep/Arp.hpp | 2 +- osdep/BSDEthernetTap.cpp | 2 +- osdep/BSDEthernetTap.hpp | 2 +- osdep/Binder.hpp | 2 +- osdep/BlockingQueue.hpp | 2 +- osdep/Http.cpp | 2 +- osdep/Http.hpp | 2 +- osdep/LinuxEthernetTap.cpp | 2 +- osdep/LinuxEthernetTap.hpp | 2 +- osdep/ManagedRoute.cpp | 2 +- osdep/ManagedRoute.hpp | 2 +- osdep/NeighborDiscovery.cpp | 2 +- osdep/NeighborDiscovery.hpp | 2 +- osdep/OSUtils.cpp | 2 +- osdep/OSUtils.hpp | 2 +- osdep/OSXEthernetTap.cpp | 2 +- osdep/OSXEthernetTap.hpp | 2 +- osdep/Phy.hpp | 2 +- osdep/PortMapper.cpp | 2 +- osdep/PortMapper.hpp | 2 +- osdep/TestEthernetTap.hpp | 2 +- osdep/Thread.hpp | 2 +- osdep/WindowsEthernetTap.cpp | 2 +- osdep/WindowsEthernetTap.hpp | 2 +- selftest.cpp | 2 +- service/OneService.cpp | 2 +- service/OneService.hpp | 2 +- service/SoftwareUpdater.cpp | 2 +- service/SoftwareUpdater.hpp | 2 +- version.h | 2 +- 97 files changed, 98 insertions(+), 98 deletions(-) (limited to 'node/Peer.cpp') diff --git a/COPYING b/COPYING index 23d42dfa..8008d3e0 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ ZeroTier One, an endpoint server for the ZeroTier virtual network layer. -Copyright © 2011–2016 ZeroTier, Inc. +Copyright © 2011–2018 ZeroTier, Inc. ZeroTier One is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 93a91933..f07650b5 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Address.hpp b/node/Address.hpp index 12c52a3f..41977af2 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Array.hpp b/node/Array.hpp index ef2611e4..de827c08 100644 --- a/node/Array.hpp +++ b/node/Array.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index 34b58e91..d58c4b56 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Buffer.hpp b/node/Buffer.hpp index f84b3774..bbf4ee37 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/C25519.hpp b/node/C25519.hpp index 950c7fed..3f22b445 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Capability.cpp b/node/Capability.cpp index 47dca1fc..fb52be8a 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Capability.hpp b/node/Capability.hpp index bec1f47f..91a46566 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index dedcccff..a849a44c 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 2eff1083..19fe5367 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index eeb0d99c..8ee67865 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index e397fd63..278ae863 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Constants.hpp b/node/Constants.hpp index 6360a693..23bebafd 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Credential.hpp b/node/Credential.hpp index e8767e22..34e94162 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index a1b0f9cb..59afb7c6 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 5aa045b9..58dc8fca 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Identity.cpp b/node/Identity.cpp index 72bea75d..9cc507f7 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Identity.hpp b/node/Identity.hpp index ab2886ad..cd24757e 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 38fd3aa0..341f3281 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index c8f52721..88f4f066 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index ee32ce72..ecfc81ab 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index fd430099..e6dfabf9 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/MAC.hpp b/node/MAC.hpp index 18fe2032..c08323a4 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Membership.cpp b/node/Membership.cpp index de5fb99d..affe7a71 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Membership.hpp b/node/Membership.hpp index 95ec2180..ad0bb73e 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index 6039d3c4..0f4a621e 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index fa6f7bd1..d5bdfdf6 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 08c96485..59959328 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 53ae05c4..cbd80524 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Network.cpp b/node/Network.cpp index e8e91174..e8a52e33 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Network.hpp b/node/Network.hpp index 1b4da7d2..db285108 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 2e07ac82..f9b16cc5 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 19823e24..4121a241 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index 63d44a46..393bcc91 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Node.cpp b/node/Node.cpp index d4b69689..af03669c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Node.hpp b/node/Node.hpp index f8236db8..82f35c56 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/NonCopyable.hpp b/node/NonCopyable.hpp index 5e8c753d..31107a50 100644 --- a/node/NonCopyable.hpp +++ b/node/NonCopyable.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 9aa44736..d7a7b4d8 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 2f6d8338..836b840b 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Packet.cpp b/node/Packet.cpp index cb9e1e0f..de059054 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Packet.hpp b/node/Packet.hpp index 8cfb5492..b96ab375 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Path.cpp b/node/Path.cpp index ca366e39..b1b3dd06 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Path.hpp b/node/Path.hpp index 6b4b9915..62d750b7 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Peer.cpp b/node/Peer.cpp index 6e46089f..71afd852 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Peer.hpp b/node/Peer.hpp index 99728736..99216bab 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 0bdfa74f..adcc2410 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 89a2db95..78098f8c 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 4a18914f..eaf01915 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 0bb78599..9ecdc400 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 584f8e11..eedc284a 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 83cd89c9..c4f107fb 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 7ddba465..ce6e8c76 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index af66545f..aa03cf0b 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Switch.cpp b/node/Switch.cpp index b2cab1d0..c3626f9f 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Switch.hpp b/node/Switch.hpp index b42389fc..4fc5453d 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Tag.cpp b/node/Tag.cpp index bde41a70..62d9cb2e 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Tag.hpp b/node/Tag.hpp index 394c7be6..d2e932c2 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Topology.cpp b/node/Topology.cpp index d1b389df..fa9868e9 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Topology.hpp b/node/Topology.hpp index b09f95cf..0bcdfb0a 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Trace.cpp b/node/Trace.cpp index 4303946b..a60a0194 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Trace.hpp b/node/Trace.hpp index 08241d37..05d5b66a 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Utils.cpp b/node/Utils.cpp index 4ac18366..a69a575e 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/Utils.hpp b/node/Utils.hpp index 54af3aec..5565fad6 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/node/World.hpp b/node/World.hpp index 26d94fcd..459470ca 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/one.cpp b/one.cpp index a1238bb8..8d4b8fc5 100644 --- a/one.cpp +++ b/one.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 @@ -93,7 +93,7 @@ using namespace ZeroTier; static OneService *volatile zt1Service = (OneService *)0; #define PROGRAM_NAME "ZeroTier One" -#define COPYRIGHT_NOTICE "Copyright (c) 2011-2017 ZeroTier, Inc." +#define COPYRIGHT_NOTICE "Copyright (c) 2011-2018 ZeroTier, Inc." #define LICENSE_GRANT \ "This is free software: you may copy, modify, and/or distribute this" ZT_EOL_S \ "work under the terms of the GNU General Public License, version 3 or" ZT_EOL_S \ diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index c06f459b..cc4e920a 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp index e26fcdb3..27e92fdb 100644 --- a/osdep/Arp.hpp +++ b/osdep/Arp.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index c0fdad9c..053df21d 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index fd2685f3..3d91dbbb 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index e3c2dc02..399ce04a 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp index 5e1a24ef..351a095a 100644 --- a/osdep/BlockingQueue.hpp +++ b/osdep/BlockingQueue.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Http.cpp b/osdep/Http.cpp index d6d0238c..16785c96 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Http.hpp b/osdep/Http.hpp index 3f98d760..b717c5c9 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index 848f3638..6ef42744 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index e05dee8c..5142eec1 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 2289b23a..8ffbed2a 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 849bddf5..873d0cfb 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp index ac95748b..d9862f3d 100644 --- a/osdep/NeighborDiscovery.cpp +++ b/osdep/NeighborDiscovery.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp index 2e7a68ba..59186289 100644 --- a/osdep/NeighborDiscovery.hpp +++ b/osdep/NeighborDiscovery.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 3325c621..aa531243 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 274b48df..324b7923 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSXEthernetTap.cpp b/osdep/OSXEthernetTap.cpp index b43d34c0..dbff6200 100644 --- a/osdep/OSXEthernetTap.cpp +++ b/osdep/OSXEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/OSXEthernetTap.hpp b/osdep/OSXEthernetTap.hpp index d0a8a99d..fe402901 100644 --- a/osdep/OSXEthernetTap.hpp +++ b/osdep/OSXEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index f71bd56c..8e683f10 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index 9aeeb8d6..a7dd3046 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp index 61015a09..fa3cdc31 100644 --- a/osdep/PortMapper.hpp +++ b/osdep/PortMapper.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/TestEthernetTap.hpp b/osdep/TestEthernetTap.hpp index 047a19b1..2f73258a 100644 --- a/osdep/TestEthernetTap.hpp +++ b/osdep/TestEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index b3011f32..35ea5035 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 93da8ad6..22b81454 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 70789e75..856c3be7 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/selftest.cpp b/selftest.cpp index 86894564..9edb4928 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/OneService.cpp b/service/OneService.cpp index 71bb6983..e65ad0e2 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/OneService.hpp b/service/OneService.hpp index 23e572d0..3b670e4a 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 39833c90..6a25dbec 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index f16c99a0..ed329b1f 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 diff --git a/version.h b/version.h index b3b2fc81..d80bec80 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 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 -- cgit v1.2.3
FieldTypeDescriptionWritable
addressstring10-digit hex ZeroTier addressno
lastUnicastFrameintegerTime of last unicast frame in ms since epochno
lastMulticastFrameintegerTime of last multicast frame in ms since epochno
versionMajorintegerMajor version of remote if knownno
versionMinorintegerMinor version of remote if knownno
versionRevintegerRevision of remote if knownno