diff --git a/attic/MulticastGroup.hpp b/attic/MulticastGroup.hpp
new file mode 100644
index 000000000..e77f96d04
--- /dev/null
+++ b/attic/MulticastGroup.hpp
@@ -0,0 +1,152 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2019 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_MULTICASTGROUP_HPP
+#define ZT_MULTICASTGROUP_HPP
+
+#include
+
+#include "Constants.hpp"
+#include "MAC.hpp"
+#include "InetAddress.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+/**
+ * A multicast group composed of a multicast MAC and a 32-bit ADI field
+ *
+ * ADI stands for additional distinguishing information. ADI is primarily for
+ * adding additional information to broadcast (ff:ff:ff:ff:ff:ff) memberships,
+ * since straight-up broadcast won't scale. Right now it's zero except for
+ * IPv4 ARP, where it holds the IPv4 address itself to make ARP into a
+ * selective multicast query that can scale.
+ *
+ * In the future we might add some kind of plugin architecture that can add
+ * ADI for things like mDNS (multicast DNS) to improve the selectivity of
+ * those protocols.
+ *
+ * MulticastGroup behaves as an immutable value object.
+ */
+class MulticastGroup
+{
+public:
+ inline MulticastGroup() :
+ _mac(),
+ _adi(0)
+ {
+ }
+
+ inline MulticastGroup(const MAC &m,uint32_t a) :
+ _mac(m),
+ _adi(a)
+ {
+ }
+
+ /**
+ * Derive the multicast group used for address resolution (ARP/NDP) for an IP
+ *
+ * @param ip IP address (port field is ignored)
+ * @return Multicast group for ARP/NDP
+ */
+ static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
+ {
+ if (ip.isV4()) {
+ // IPv4 wants broadcast MACs, so we shove the V4 address itself into
+ // the Multicast Group ADI field. Making V4 ARP work is basically why
+ // ADI was added, as well as handling other things that want mindless
+ // Ethernet broadcast to all.
+ return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData())));
+ } else if (ip.isV6()) {
+ // IPv6 is better designed in this respect. We can compute the IPv6
+ // multicast address directly from the IP address, and it gives us
+ // 24 bits of uniqueness. Collisions aren't likely to be common enough
+ // to care about.
+ const unsigned char *a = (const unsigned char *)ip.rawIpData();
+ return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
+ }
+ return MulticastGroup();
+ }
+
+ /**
+ * @return Multicast address
+ */
+ inline const MAC &mac() const { return _mac; }
+
+ /**
+ * @return Additional distinguishing information
+ */
+ inline uint32_t adi() const { return _adi; }
+
+ /**
+ * Compute a 32-bit randomized identifier for this group
+ *
+ * This is a 32-bit fnv1a hash of the MAC and ADI. It's part of the protocol as it's
+ * used to generate unique identifiers for multicast groups for multicast lookup, so
+ * don't change it lightly.
+ */
+ inline uint32_t id32() const
+ {
+ uint32_t h = 0x811c9dc5;
+ const uint64_t m = _mac.toInt();
+ const uint32_t p = 0x1000193;
+ h ^= (uint32_t)(m >> 40) & 0xff; h *= p;
+ h ^= (uint32_t)(m >> 32) & 0xff; h *= p;
+ h ^= (uint32_t)(m >> 24) & 0xff; h *= p;
+ h ^= (uint32_t)(m >> 16) & 0xff; h *= p;
+ h ^= (uint32_t)(m >> 8) & 0xff; h *= p;
+ h ^= (uint32_t)m & 0xff; h *= p;
+ h ^= _adi >> 24; h *= p;
+ h ^= (_adi >> 16) & 0xff; h *= p;
+ h ^= (_adi >> 8) & 0xff; h *= p;
+ h ^= _adi & 0xff; h *= p;
+ return h;
+ }
+
+ inline unsigned long hashCode() const { return (_mac.hashCode() + (unsigned long)_adi); }
+
+ 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;
+ else if (_mac == g._mac)
+ return (_adi < g._adi);
+ return false;
+ }
+ 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;
+ uint32_t _adi;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/attic/MulticastSubscriptions.hpp b/attic/MulticastSubscriptions.hpp
new file mode 100644
index 000000000..0a73150a4
--- /dev/null
+++ b/attic/MulticastSubscriptions.hpp
@@ -0,0 +1,123 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2019 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_MULTICASTSUBSCRIPTIONS_HPP
+#define ZT_MULTICASTSUBSCRIPTIONS_HPP
+
+#include "Constants.hpp"
+#include "MulticastGroup.hpp"
+#include "Identity.hpp"
+#include "Buffer.hpp"
+
+namespace ZeroTier {
+
+/**
+ * A compact collection of multicast subscriptions identified by 32-bit hash values
+ */
+class MulticastSubscriptions
+{
+public:
+ inline MulticastSubscriptions() : _signatureLength(0) {}
+
+ inline void add(const MulticastGroup &mg)
+ {
+ if (_subscriptions.size() < ZT_MAX_MULTICAST_SUBSCRIPTIONS)
+ _subscriptions.push_back(mg.id32());
+ }
+
+ inline bool sign(const Identity &signer,const int64_t ts)
+ {
+ _ts = ts;
+ std::sort(_subscriptions.begin(),_subscriptions.end());
+ _subscriptions.erase(std::unique(_subscriptions.begin(),_subscriptions.end()),_subscriptions.end());
+
+ _SRec tmp;
+ tmp.ts = Utils::hton((uint64_t)ts);
+ for(unsigned long i=0,j=(unsigned long)_subscriptions.size();i 0);
+ }
+
+ inline bool verify(const Identity &signer)
+ {
+ if ((_signatureLength == 0)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
+ return false;
+ _SRec tmp;
+ tmp.ts = Utils::hton((uint64_t)_ts);
+ for(unsigned long i=0,j=(unsigned long)_subscriptions.size();i
+ inline void serialize(Buffer &b) const
+ {
+ b.append((uint64_t)_ts);
+ b.append((uint16_t)_subscriptions.size());
+ for(std::vector::const_iterator i(_subscriptions.begin());i!=_subscriptions.end();++i)
+ b.append(*i);
+ b.append((uint16_t)_signatureLength);
+ b.append(_signature,_signatureLength);
+ }
+
+ template
+ inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0)
+ {
+ unsigned int p = startAt;
+ _ts = (int64_t)(b.template at(p)); p += 8;
+ _subscriptions.resize(b.template at(p)); p += 2;
+ for(std::vector::iterator i(_subscriptions.begin());i!=_subscriptions.end();++i) {
+ *i = b.template at(p);
+ p += 4;
+ }
+ _signatureLength = b.template at(p); p += 2;
+ if (_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)
+ throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
+ memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
+ return (p - startAt);
+ }
+
+private:
+ ZT_PACKED_STRUCT(struct _SRec {
+ uint64_t ts;
+ uint32_t g[ZT_MAX_MULTICAST_SUBSCRIPTIONS];
+ });
+
+ int64_t _ts;
+ std::vector _subscriptions;
+ unsigned int _signatureLength;
+ uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index 2da12598f..8972a4507 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -130,7 +130,7 @@ extern "C" {
/**
* Maximum number of multicast group subscriptions per network
*/
-#define ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS 4096
+#define ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS 2048
/**
* Rules engine revision ID, which specifies rules engine capabilities
diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp
index a3feff8b7..00d05de45 100644
--- a/node/Hashtable.hpp
+++ b/node/Hashtable.hpp
@@ -383,26 +383,11 @@ public:
private:
template
- static inline unsigned long _hc(const O &obj)
- {
- return (unsigned long)obj.hashCode();
- }
- static inline unsigned long _hc(const uint64_t i)
- {
- return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses
- }
- static inline unsigned long _hc(const uint32_t i)
- {
- return ((unsigned long)i * (unsigned long)0x9e3779b1);
- }
- static inline unsigned long _hc(const uint16_t i)
- {
- return ((unsigned long)i * (unsigned long)0x9e3779b1);
- }
- static inline unsigned long _hc(const int i)
- {
- return ((unsigned long)i * (unsigned long)0x9e3379b1);
- }
+ static inline unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
+ static inline unsigned long _hc(const uint64_t i) { return (unsigned long)(i ^ (i >> 32)); }
+ static inline unsigned long _hc(const uint32_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
+ static inline unsigned long _hc(const uint16_t i) { return ((unsigned long)i * (unsigned long)0x9e3779b1); }
+ static inline unsigned long _hc(const int i) { return ((unsigned long)i * (unsigned long)0x9e3379b1); }
inline void _grow()
{
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 8e3803a67..f39c78281 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -75,7 +75,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
return _doHELLO(RR,tPtr,false);
}
- const SharedPtr peer(RR->topology->getPeer(tPtr,sourceAddress));
+ const SharedPtr peer(RR->topology->get(sourceAddress));
if (peer) {
if (!trusted) {
if (!dearmor(peer->key())) {
@@ -170,7 +170,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
case Packet::ERROR_IDENTITY_COLLISION:
// This is a trusted upstream telling us our 5-digit ID is taken. This
// causes the node to generate another.
- if (RR->topology->isUpstream(peer->identity()))
+ if (RR->topology->isRoot(peer->identity()))
RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
break;
@@ -283,7 +283,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
return true;
}
- SharedPtr peer(RR->topology->getPeer(tPtr,id.address()));
+ SharedPtr peer(RR->topology->get(id.address()));
if (peer) {
// We already have an identity with this address -- check for collisions
if (!alreadyAuthenticated) {
@@ -351,7 +351,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
return true;
}
- peer = RR->topology->addPeer(tPtr,newPeer);
+ peer = RR->topology->add(newPeer);
// Continue at // VALID
}
@@ -363,7 +363,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->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
+ RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
}
// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
@@ -451,13 +451,13 @@ 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->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now());
+ RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now());
} break;
case Packet::VERB_WHOIS:
- if (RR->topology->isUpstream(peer->identity())) {
+ if (RR->topology->isRoot(peer->identity())) {
const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
- RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id))));
+ RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->add(SharedPtr(new Peer(RR,RR->identity,id))));
}
break;
@@ -550,9 +550,9 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer)
{
- if (RR->topology->isUpstream(peer->identity())) {
+ if (RR->topology->isRoot(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));
+ const SharedPtr rendezvousWith(RR->topology->get(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];
@@ -1021,7 +1021,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
const bool amAnchor = (std::find(anchors.begin(),anchors.end(),RR->identity.address()) != anchors.end());
for(std::list::iterator ra(recipients.begin());ra!=recipients.end();) {
- SharedPtr recipient(RR->topology->getPeer(tPtr,*ra));
+ SharedPtr recipient(RR->topology->get(*ra));
if ((recipient)&&((recipient->remoteVersionProtocol() < 10)||(amAnchor))) {
Packet outp(*ra,RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
outp.append(field(ZT_PACKET_IDX_PAYLOAD,recipientsOffset - ZT_PACKET_IDX_PAYLOAD),recipientsOffset - ZT_PACKET_IDX_PAYLOAD);
diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp
index 15d2f8780..0439351a4 100644
--- a/node/InetAddress.cpp
+++ b/node/InetAddress.cpp
@@ -38,6 +38,7 @@ namespace ZeroTier {
const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0);
const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0);
+const InetAddress InetAddress::NIL;
InetAddress::IpScope InetAddress::ipScope() const
{
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index 729b1ac5e..c733792a3 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -64,6 +64,11 @@ struct InetAddress : public sockaddr_storage
*/
static const InetAddress LO6;
+ /**
+ * Null address
+ */
+ static const InetAddress NIL;
+
/**
* IP address scope
*
diff --git a/node/Locator.hpp b/node/Locator.hpp
index 6fb7c2e72..a26a5b1d3 100644
--- a/node/Locator.hpp
+++ b/node/Locator.hpp
@@ -58,10 +58,11 @@ namespace ZeroTier {
class Locator
{
public:
- inline Locator() : _signatureLength(0) {}
+ inline Locator() : _ts(0),_signatureLength(0) {}
inline const Identity &id() const { return _id; }
inline const Identity &signer() const { return ((_signedBy) ? _signedBy : _id); }
+ inline int64_t timestamp() const { return _ts; }
inline const std::vector &phy() const { return _physical; }
inline const std::vector &virt() const { return _virtual; }
@@ -186,10 +187,9 @@ public:
/**
* Decode TXT records
*
- * The supplied TXT records must be sorted in ascending natural sort order prior
- * to calling this method. The iterators supplied must be read iterators that
- * point to string objects supporting the c_str() method, which can be Str or
- * std::string.
+ * TXT records can be provided as an iterator over std::string, Str, or char *
+ * values, and TXT records can be provided in any order. Any oversize or empty
+ * entries will be ignored.
*
* This method checks the decoded locator's signature using the supplied DNS TXT
* record signing public key. False is returned if the TXT records are invalid,
@@ -202,11 +202,22 @@ public:
uint8_t dec[256],s384[48];
Buffer<65536> *tmp = nullptr;
try {
- tmp = new Buffer<65536>();
+ std::vector txtRecords;
while (start != end) {
- tmp->append(dec,Utils::b64d(start->c_str(),dec,sizeof(dec)));
+ try {
+ Str ts(start);
+ if (ts.length() > 2)
+ txtRecords.push_back(ts);
+ } catch ( ... ) {} // skip any records that trigger out of bounds exceptions
++start;
}
+ if (txtRecords.empty())
+ return false;
+ std::sort(txtRecords.begin(),txtRecords.end());
+
+ tmp = new Buffer<65536>();
+ for(std::vector::const_iterator i(txtRecords.begin());i!=txtRecords.end();++i)
+ tmp->append(dec,Utils::b64d(i->c_str() + 2,dec,sizeof(dec)));
if (tmp->size() <= ZT_ECC384_SIGNATURE_SIZE) {
delete tmp;
@@ -219,8 +230,8 @@ public:
}
deserialize(*tmp,0);
-
delete tmp;
+
return verify();
} catch ( ... ) {
if (tmp) delete tmp;
@@ -235,10 +246,10 @@ public:
b.append((uint8_t)0); // version/flags, currently 0
b.append((uint64_t)_ts);
- _id.serialise(b,false);
+ _id.serialize(b,false);
if (_signedBy) {
b.append((uint8_t)1); // number of signers, current max is 1
- _signedBy.serialize(b,false);
+ _signedBy.serialize(b,false); // be sure not to include private key!
} else {
b.append((uint8_t)0); // signer is _id
}
@@ -282,7 +293,7 @@ public:
_virtual.resize(virtualCount);
for(unsigned int i=0;i(p); p += 2;
+ _signatureLength = b.template at(p); p += 2;
if (_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength);
diff --git a/node/MAC.hpp b/node/MAC.hpp
index d0c49c0bc..da02f6409 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 { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); }
+ inline uint8_t operator[](unsigned int i) const { return (uint8_t)(_m >> (40 - (i * 8))); }
/**
* @return 6, which is the number of bytes in a MAC, for container compliance
@@ -230,7 +230,7 @@ public:
}
inline MAC &operator=(const uint64_t m)
{
- _m = m;
+ _m = m & 0xffffffffffffULL;
return *this;
}
diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp
index 866d648fb..f870bee58 100644
--- a/node/MulticastGroup.hpp
+++ b/node/MulticastGroup.hpp
@@ -29,6 +29,7 @@
#include
+#include "Constants.hpp"
#include "MAC.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
@@ -90,17 +91,10 @@ public:
return MulticastGroup();
}
- /**
- * @return Multicast address
- */
inline const MAC &mac() const { return _mac; }
-
- /**
- * @return Additional distinguishing information
- */
inline uint32_t adi() const { return _adi; }
- inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); }
+ inline unsigned long hashCode() const { return (_mac.hashCode() + (unsigned long)_adi); }
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)); }
diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp
index f64738dea..56a800a45 100644
--- a/node/Multicaster.cpp
+++ b/node/Multicaster.cpp
@@ -243,10 +243,6 @@ void Multicaster::send(
Address explicitGatherPeers[16];
unsigned int numExplicitGatherPeers = 0;
- SharedPtr bestRoot(RR->topology->getUpstreamPeer());
- if (bestRoot)
- explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address();
-
explicitGatherPeers[numExplicitGatherPeers++] = network->controller();
Address ac[ZT_MAX_NETWORK_SPECIALISTS];
diff --git a/node/Network.cpp b/node/Network.cpp
index 0b89d487d..fb7780753 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -1246,15 +1246,12 @@ void Network::clean()
_multicastGroupsBehindMe.erase(*mg);
}
}
-
{
Address *a = (Address *)0;
Membership *m = (Membership *)0;
Hashtable::Iterator i(_memberships);
while (i.next(a,m)) {
- if (!RR->topology->getPeerNoCache(*a))
- _memberships.erase(*a);
- else m->clean(now,_config);
+ m->clean(now,_config);
}
}
}
@@ -1403,42 +1400,17 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
}
}
-void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup)
+void Network::_sendUpdatesToMembers(void *tPtr)
{
// Assumes _lock is locked
- const int64_t now = RR->node->now();
-
- std::vector groups;
- if (newMulticastGroup)
- groups.push_back(*newMulticastGroup);
- else groups = _allMulticastGroups();
-
- std::vector alwaysAnnounceTo;
-
- if ((newMulticastGroup)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) {
- if (!newMulticastGroup)
- _lastAnnouncedMulticastGroupsUpstream = now;
-
- alwaysAnnounceTo = _config.alwaysContactAddresses();
- if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),controller()) == alwaysAnnounceTo.end())
- alwaysAnnounceTo.push_back(controller());
- const std::vector upstreams(RR->topology->upstreamAddresses());
- for(std::vector::const_iterator a(upstreams.begin());a!=upstreams.end();++a) {
- if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a) == alwaysAnnounceTo.end())
- alwaysAnnounceTo.push_back(*a);
- }
- std::sort(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end());
-
- for(std::vector::const_iterator a(alwaysAnnounceTo.begin());a!=alwaysAnnounceTo.end();++a)
- _announceMulticastGroupsTo(tPtr,*a,groups);
- }
-
+ const std::vector groups(_allMulticastGroups());
+ _announceMulticastGroupsTo(tPtr,controller(),groups);
{
Address *a = (Address *)0;
Membership *m = (Membership *)0;
Hashtable::Iterator i(_memberships);
while (i.next(a,m)) {
- if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config)) && (!std::binary_search(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a)) )
+ if (m->isAllowedOnNetwork(_config))
_announceMulticastGroupsTo(tPtr,*a,groups);
}
}
diff --git a/node/Network.hpp b/node/Network.hpp
index 1f25122da..4c7af8da4 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -193,10 +193,10 @@ public:
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(tPtr,&mg);
+ _sendUpdatesToMembers(tPtr);
}
}
-
+
/**
* Unsubscribe from a multicast group
*
@@ -295,7 +295,7 @@ public:
inline void sendUpdatesToMembers(void *tPtr)
{
Mutex::Lock _l(_lock);
- _sendUpdatesToMembers(tPtr,(const MulticastGroup *)0);
+ _sendUpdatesToMembers(tPtr);
}
/**
@@ -432,7 +432,7 @@ private:
ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
bool _gate(const SharedPtr &peer);
- void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup);
+ void _sendUpdatesToMembers(void *tPtr);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups);
std::vector _allMulticastGroups() const;
diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp
index 2c8aea3ac..d25c67dbd 100644
--- a/node/NetworkConfig.hpp
+++ b/node/NetworkConfig.hpp
@@ -104,7 +104,7 @@ namespace ZeroTier {
#define ZT_NETWORKCONFIG_DICT_CAPACITY (1024 + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
// Dictionary capacity needed for max size network meta-data
-#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024
+#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 2048
// Network config version
#define ZT_NETWORKCONFIG_VERSION 7
diff --git a/node/Node.cpp b/node/Node.cpp
index 217dd33fd..b8301c58b 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -126,7 +126,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
m += sws;
RR->mc = new (m) Multicaster(RR);
m += mcs;
- RR->topology = new (m) Topology(RR,tptr);
+ RR->topology = new (m) Topology(RR,RR->identity);
m += topologys;
RR->sa = new (m) SelfAwareness(RR);
} catch ( ... ) {
@@ -190,6 +190,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
+/*
// Function object used to traverse the peer list, check peer status, and ping
// those that need pinging.
struct _PingPeersThatNeedPing
@@ -254,6 +255,7 @@ struct _PingPeersThatNeedPing
bool online;
};
+*/
ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
{
@@ -282,6 +284,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
_localControllerAuthorizations_m.unlock();
}
+/*
// (1) Get peers we should remain connected to and (2) get networks that need config.
Hashtable< Address,std::vector > alwaysContact;
RR->topology->getAlwaysContact(alwaysContact);
@@ -322,6 +325,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
_online = pfunc.online;
if (oldOnline != _online)
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
+*/
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@@ -337,7 +341,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) {
_lastHousekeepingRun = now;
try {
- RR->topology->doPeriodicTasks(tptr,now);
+ RR->topology->doPeriodicTasks(now);
RR->sa->clean(now);
RR->mc->clean(now);
} catch ( ... ) {
@@ -454,7 +458,7 @@ ZT_PeerList *Node::peers() const
p->latency = pi->second->latency(_now);
if (p->latency >= 0xffff)
p->latency = -1;
- p->role = RR->topology->role(pi->second->identity().address());
+ p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_PLANET : ZT_PEER_ROLE_LEAF;
std::vector< SharedPtr > paths(pi->second->paths(_now));
SharedPtr bestp(pi->second->getAppropriatePath(_now,false));
diff --git a/node/Root.hpp b/node/Root.hpp
new file mode 100644
index 000000000..0b6b4f231
--- /dev/null
+++ b/node/Root.hpp
@@ -0,0 +1,223 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2019 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_ROOT_HPP
+#define ZT_ROOT_HPP
+
+#include "Constants.hpp"
+#include "Str.hpp"
+#include "ECC384.hpp"
+#include "Locator.hpp"
+#include "InetAddress.hpp"
+#include "Utils.hpp"
+#include "Identity.hpp"
+#include "Mutex.hpp"
+
+namespace ZeroTier {
+
+/**
+ * A root entry pointing to a node capable of global identity lookup and indirect transit
+ *
+ * Root entries point to DNS records that contain TXT entries that decode to Locator objects
+ * pointing to actual root nodes. A default root identity and static addresses can also be
+ * provided as fallback if DNS is not available.
+ *
+ * Note that root identities can change if DNS returns a different result, but that DNS entries
+ * are authenticated using their own signature scheme. This allows a root DNS name to serve
+ * up different roots based on factors like location or relative load of different roots.
+ *
+ * It's also possible to create a root with no DNS and no DNS validator public key. This root
+ * will be a static entry pointing to a single root identity and set of physical addresses.
+ *
+ * This object is thread-safe and may be concurrently accessed and updated.
+ */
+class Root
+{
+public:
+ inline Root() : _dnsPublicKeySize(0) {}
+ inline Root(const Root &r) { *this = r; }
+
+ /**
+ * Create a new root entry
+ *
+ * @param dn DNS name
+ * @param dnspk DNS public key for record validation
+ * @param dnspksize Size of DNS public key (currently always the size of a NIST P-384 point compressed public key)
+ * @param dflId Default identity if DNS is not available
+ * @param dflAddrs Default IP addresses if DNS is not available
+ */
+ template
+ inline Root(S dn,const uint8_t *const dnspk,const unsigned int dnspksize,const Identity &dflId,const std::vector &dflAddrs) :
+ _defaultIdentity(dflId),
+ _defaultAddresses(dflAddrs),
+ _dnsName(dn),
+ _dnsPublicKeySize(dnspksize)
+ {
+ if (dnspksize != 0) {
+ if (dnspksize > sizeof(_dnsPublicKey))
+ throw ZT_EXCEPTION_INVALID_ARGUMENT;
+ memcpy(_dnsPublicKey,dnspk,dnspksize);
+ }
+ }
+
+ inline Root &operator=(const Root &r)
+ {
+ Mutex::Lock l(_lock);
+ Mutex::Lock rl(r._lock);
+ _defaultIdentity = r._defaultIdentity;
+ _defaultAddresses = r._defaultAddresses;
+ _dnsName = r._dnsName;
+ _lastFetchedLocator = r._lastFetchedLocator;
+ _dnsPublicKeySize = r._dnsPublicKeySize;
+ memcpy(_dnsPublicKey,r._dnsPublicKey,_dnsPublicKeySize);
+ return *this;
+ }
+
+ /**
+ * @return Current identity (either default or latest locator)
+ */
+ inline const Identity id() const
+ {
+ Mutex::Lock l(_lock);
+ if (_lastFetchedLocator.id())
+ return _lastFetchedLocator.id();
+ return _defaultIdentity;
+ }
+
+ /**
+ * @param id Identity to check
+ * @return True if identity equals this root's current identity
+ */
+ inline bool is(const Identity &id) const
+ {
+ Mutex::Lock l(_lock);
+ return ((_lastFetchedLocator.id()) ? (id == _lastFetchedLocator.id()) : (id == _defaultIdentity));
+ }
+
+ /**
+ * @return Current ZeroTier address (either default or latest locator)
+ */
+ inline const Address address() const
+ {
+ Mutex::Lock l(_lock);
+ if (_lastFetchedLocator.id())
+ return _lastFetchedLocator.id().address();
+ return _defaultIdentity.address();
+ }
+
+ /**
+ * @return DNS name for this root (or empty string if none)
+ */
+ inline const Str dnsName() const
+ {
+ Mutex::Lock l(_lock);
+ return _dnsName;
+ }
+
+ /**
+ * @return Latest locator
+ */
+ inline Locator locator() const
+ {
+ Mutex::Lock l(_lock);
+ return _lastFetchedLocator;
+ }
+
+ /**
+ * @return Timestamp of latest retrieved locator
+ */
+ inline int64_t locatorTimestamp() const
+ {
+ Mutex::Lock l(_lock);
+ return _lastFetchedLocator.timestamp();
+ }
+
+ /**
+ * Pick a random physical address
+ *
+ * @return Physical address or InetAddress::NIL if none are available
+ */
+ inline const InetAddress randomPhysicalAddress() const
+ {
+ Mutex::Lock l(_lock);
+ if (_lastFetchedLocator.phy().empty()) {
+ if (_defaultAddresses.empty())
+ return InetAddress::NIL;
+ return _defaultAddresses[(unsigned long)Utils::random() % (unsigned long)_defaultAddresses.size()];
+ }
+ return _lastFetchedLocator.phy()[(unsigned long)Utils::random() % (unsigned long)_lastFetchedLocator.phy().size()];
+ }
+
+ /**
+ * Update locator, returning true if new locator is valid and newer than existing
+ */
+ inline bool updateLocator(const Locator &loc)
+ {
+ if (!loc.verify())
+ return false;
+ Mutex::Lock l(_lock);
+ if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
+ _lastFetchedLocator = loc;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Update this root's locator from a series of TXT records
+ */
+ template
+ inline bool updateLocatorFromTxt(I start,I end)
+ {
+ try {
+ Mutex::Lock l(_lock);
+ if (_dnsPublicKeySize != ZT_ECC384_PUBLIC_KEY_SIZE)
+ return false;
+ Locator loc;
+ if (!loc.decodeTxtRecords(start,end,_dnsPublicKey))
+ return false;
+ if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
+ _lastFetchedLocator = loc;
+ return true;
+ }
+ return false;
+ } catch ( ... ) {}
+ return false;
+ }
+
+private:
+ Identity _defaultIdentity;
+ std::vector _defaultAddresses;
+ Str _dnsName;
+ Locator _lastFetchedLocator;
+ unsigned int _dnsPublicKeySize;
+ uint8_t _dnsPublicKey[ZT_ECC384_PUBLIC_KEY_SIZE];
+ Mutex _lock;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/node/Str.hpp b/node/Str.hpp
index 7f2974461..a85a29035 100644
--- a/node/Str.hpp
+++ b/node/Str.hpp
@@ -33,6 +33,8 @@
#include "MAC.hpp"
#include "InetAddress.hpp"
+#include
+
#define ZT_STR_CAPACITY 254
namespace ZeroTier {
@@ -58,6 +60,10 @@ public:
_s[0] = 0;
(*this) << s;
}
+ inline Str(const std::string &s)
+ {
+ *this = s;
+ }
inline Str &operator=(const Str &s)
{
@@ -71,6 +77,19 @@ public:
_s[0] = 0;
return ((*this) << s);
}
+ inline Str &operator=(const std::string &s)
+ {
+ if (s.length() > ZT_STR_CAPACITY) {
+ _l = 0;
+ _s[0] = 0;
+ throw ZT_EXCEPTION_OUT_OF_BOUNDS;
+ } else {
+ _l = (uint8_t)s.length();
+ memcpy(_s,s.data(),s.length());
+ _s[s.length()] = 0;
+ }
+ return *this;
+ }
inline char operator[](const unsigned int i) const
{
@@ -82,6 +101,7 @@ public:
inline void clear() { _l = 0; _s[0] = 0; }
inline const char *c_str() const { return _s; }
inline unsigned int length() const { return (unsigned int)_l; }
+ inline bool empty() const { return (_l == 0); }
inline iterator begin() { return (iterator)_s; }
inline iterator end() { return (iterator)(_s + (unsigned long)_l); }
inline const_iterator begin() const { return (const_iterator)_s; }
@@ -113,6 +133,7 @@ public:
}
_s[(unsigned long)(_l++)] = c;
_s[(unsigned long)_l] = 0;
+ return *this;
}
inline Str &operator<<(const unsigned long n)
{
@@ -142,6 +163,8 @@ public:
return ((*this) << a.toString(tmp));
}
+ inline operator bool() const { return (_l != 0); }
+
inline bool operator==(const Str &s) const { return ((_l == s._l)&&(strcmp(_s,s._s) == 0)); }
inline bool operator!=(const Str &s) const { return ((_l != s._l)||(strcmp(_s,s._s) != 0)); }
inline bool operator<(const Str &s) const { return ((_l < s._l)&&(strcmp(_s,s._s) < 0)); }
diff --git a/node/Switch.cpp b/node/Switch.cpp
index ce4ed0280..22521d614 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -73,7 +73,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
return;
if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr))
return;
- const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr));
+ const SharedPtr peer(RR->topology->get(beaconAddr));
if (peer) { // we'll only respond to beacons from known peers
if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
_lastBeaconResponse = now;
@@ -96,12 +96,13 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
// 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(tPtr,destination);
+ SharedPtr relayTo = RR->topology->get(destination);
if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) {
// Don't know peer or no direct path -- so relay via someone upstream
- relayTo = RR->topology->getUpstreamPeer();
- if (relayTo)
- relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true);
+ // TODO
+ //relayTo = RR->topology->getUpstreamPeer();
+ //if (relayTo)
+ // relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true);
}
}
} else {
@@ -163,22 +164,25 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
Packet packet(data,len);
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
packet.incrementHops();
- SharedPtr relayTo = RR->topology->getPeer(tPtr,destination);
+ SharedPtr relayTo = RR->topology->get(destination);
if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) {
if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) {
- const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source));
+ const SharedPtr sourcePeer(RR->topology->get(source));
if (sourcePeer)
relayTo->introduce(tPtr,now,sourcePeer);
}
} else {
+ // TODO
+ /*
relayTo = RR->topology->getUpstreamPeer();
if ((relayTo)&&(relayTo->address() != source)) {
if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) {
- const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source));
+ const SharedPtr sourcePeer(RR->topology->get(source));
if (sourcePeer)
relayTo->introduce(tPtr,now,sourcePeer);
}
}
+ */
}
}
} else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
@@ -402,7 +406,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const
// 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(tPtr,toZT));
+ SharedPtr toPeer(RR->topology->get(toZT));
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked");
@@ -763,7 +767,7 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt)
}
_txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt));
}
- if (!RR->topology->getPeer(tPtr,dest))
+ if (!RR->topology->get(dest))
requestWhois(tPtr,RR->node->now(),dest);
}
}
@@ -781,6 +785,8 @@ void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
else last = now;
}
+ // TODO
+ /*
const SharedPtr upstream(RR->topology->getUpstreamPeer());
if (upstream) {
Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS);
@@ -788,6 +794,7 @@ void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
RR->node->expectReplyTo(outp.packetId());
send(tPtr,outp,true);
}
+ */
}
void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer)
@@ -840,7 +847,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
} else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) {
_txQueue.erase(txi++);
} else {
- if (!RR->topology->getPeer(tPtr,txi->dest))
+ if (!RR->topology->get(txi->dest))
needWhois.push_back(txi->dest);
++txi;
}
@@ -857,7 +864,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
rq->timestamp = 0;
} else {
const Address src(rq->frag0.source());
- if (!RR->topology->getPeer(tPtr,src))
+ if (!RR->topology->get(src))
requestWhois(tPtr,now,src);
}
}
@@ -905,16 +912,19 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt)
const int64_t now = RR->node->now();
const Address destination(packet.destination());
- const SharedPtr peer(RR->topology->getPeer(tPtr,destination));
+ const SharedPtr peer(RR->topology->get(destination));
if (peer) {
viaPath = peer->getAppropriatePath(now,false);
if (!viaPath) {
+ // TODO
+ /*
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->getAppropriatePath(now,false))) ) {
if (!(viaPath = peer->getAppropriatePath(now,true)))
return false;
}
+ */
}
} else {
return false;
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 650cb44e6..be40b438a 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -45,6 +45,7 @@
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
+#include "Root.hpp"
namespace ZeroTier {
@@ -56,8 +57,9 @@ class RuntimeEnvironment;
class Topology
{
public:
- inline Topology(const RuntimeEnvironment *renv,void *tPtr) :
+ inline Topology(const RuntimeEnvironment *renv,const Identity &myId) :
RR(renv),
+ _myIdentity(myId),
_numConfiguredPhysicalPaths(0) {}
inline ~Topology() {}
@@ -71,7 +73,7 @@ public:
* @param peer Peer to add
* @return New or existing peer (should replace 'peer')
*/
- inline SharedPtr addPeer(void *tPtr,const SharedPtr &peer)
+ inline SharedPtr add(const SharedPtr &peer)
{
SharedPtr np;
{
@@ -91,13 +93,28 @@ public:
* @param zta ZeroTier address of peer
* @return Peer or NULL if not found
*/
- inline SharedPtr getPeer(void *tPtr,const Address &zta) const
+ inline SharedPtr get(const Address &zta)
{
- if (zta == RR->identity.address())
+ if (zta == _myIdentity.address())
return SharedPtr();
- Mutex::Lock _l(_peers_m);
+
+ Mutex::Lock l1(_peers_m);
const SharedPtr *const ap = _peers.get(zta);
- return ((ap) ? *ap : SharedPtr());
+ if (ap)
+ return *ap;
+
+ Mutex::Lock l2(_roots_m);
+ for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) {
+ if (r->address() == zta) {
+ try {
+ SharedPtr rp(new Peer(RR,_myIdentity,r->id()));
+ _peers[zta] = rp;
+ return rp;
+ } catch ( ... ) {}
+ }
+ }
+
+ return SharedPtr();
}
/**
@@ -107,8 +124,8 @@ public:
*/
inline Identity getIdentity(void *tPtr,const Address &zta)
{
- if (zta == RR->identity.address()) {
- return RR->identity;
+ if (zta == _myIdentity.address()) {
+ return _myIdentity;
} else {
Mutex::Lock _l(_peers_m);
const SharedPtr *const ap = _peers.get(zta);
@@ -118,25 +135,6 @@ public:
return Identity();
}
- /**
- * Get a peer only if it is presently in memory (no disk cache)
- *
- * This also does not update the lastUsed() time for peers, which means
- * that it won't prevent them from falling out of RAM. This is currently
- * used in the Cluster code to update peer info without forcing all peers
- * across the entire cluster to remain in memory cache.
- *
- * @param zta ZeroTier address
- */
- inline SharedPtr getPeerNoCache(const Address &zta)
- {
- Mutex::Lock _l(_peers_m);
- const SharedPtr *const ap = _peers.get(zta);
- if (ap)
- return *ap;
- return SharedPtr();
- }
-
/**
* Get a Path object for a given local and remote physical address, creating if needed
*
@@ -153,36 +151,24 @@ public:
return p;
}
- inline SharedPtr getUpstreamPeer() const
+ /**
+ * @param id Identity to check
+ * @return True if this identity corresponds to a root
+ */
+ inline bool isRoot(const Identity &id) const
{
- // TODO
- return SharedPtr();
- }
-
- inline bool isUpstream(const Identity &id) const
- {
- // TODO
+ Mutex::Lock l(_roots_m);
+ for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) {
+ if (r->is(id))
+ return true;
+ }
return false;
}
- inline ZT_PeerRole role(const Address &ztaddr) const
- {
- // TODO
- return ZT_PEER_ROLE_LEAF;
- }
-
- inline void getAlwaysContact(Hashtable< Address,std::vector > &eps) const
- {
- // TODO
- }
-
- inline std::vector upstreamAddresses() const
- {
- // TODO
- return std::vector();
- }
-
- inline void doPeriodicTasks(void *tPtr,int64_t now)
+ /**
+ * Do periodic tasks such as database cleanup
+ */
+ inline void doPeriodicTasks(int64_t now)
{
{
Mutex::Lock _l1(_peers_m);
@@ -357,11 +343,14 @@ public:
private:
const RuntimeEnvironment *const RR;
+ const Identity _myIdentity;
std::pair _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
unsigned int _numConfiguredPhysicalPaths;
+ std::vector _roots;
Hashtable< Address,SharedPtr > _peers;
- Mutex _peers_m;
Hashtable< Path::HashKey,SharedPtr > _paths;
+ Mutex _roots_m;
+ Mutex _peers_m;
Mutex _paths_m;
};