summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Constants.hpp5
-rw-r--r--node/IncomingPacket.cpp4
-rw-r--r--node/InetAddress.hpp22
-rw-r--r--node/Path.hpp2
-rw-r--r--node/Peer.cpp28
-rw-r--r--node/Peer.hpp19
-rw-r--r--node/SelfAwareness.cpp41
-rw-r--r--node/SelfAwareness.hpp8
-rw-r--r--node/Topology.cpp30
-rw-r--r--node/Topology.hpp38
10 files changed, 102 insertions, 95 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp
index d4944b5e..58b5f4b4 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -302,11 +302,6 @@
#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 2) + ZT_PING_CHECK_DELAY)
/**
- * Path activity timeout (for non-fixed paths)
- */
-#define ZT_PEER_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT
-
-/**
* Stop relaying via peers that have not responded to direct sends
*
* When we send something (including frames), we generally expect a response.
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 17eb09d9..e2819f0b 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -264,9 +264,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
if (RR->topology->isSupernode(id.address())) {
RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision);
- RR->sa->iam(destAddr,true);
+ RR->sa->iam(_remoteAddress,destAddr,true);
} else {
- RR->sa->iam(destAddr,false);
+ RR->sa->iam(_remoteAddress,destAddr,false);
}
Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index 2ed23761..43fcc333 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -74,21 +74,19 @@ struct InetAddress : public sockaddr_storage
/**
* IP address scope
*
- * Be sure the integer values of these start at 0 and increment
- * monotonically without gaps, as they're used as an array index.
- * The NONE entry must be the last, since it's the count. It's
- * okay to change these since they are not exported via the API.
+ * Do not change these numeric index values without taking a look
+ * at SelfAwareness. Values 1-5 are mapped onto an array index.
*/
enum IpScope
{
- IP_SCOPE_LOOPBACK = 0, // 127.0.0.1
- IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other multicast IPs
- IP_SCOPE_LINK_LOCAL = 2, // 169.254.x.x, IPv6 LL
- IP_SCOPE_PRIVATE = 3, // 10.x.x.x, etc.
- IP_SCOPE_PSEUDOPRIVATE = 4, // 28.x.x.x, etc. -- unofficially unrouted IP blocks often "bogarted"
- IP_SCOPE_SHARED = 5, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT
- IP_SCOPE_GLOBAL = 6, // globally routable IP address (all others)
- IP_SCOPE_NONE = 7 // not an IP address -- also the number of classes, must be last entry
+ IP_SCOPE_NONE = 0, // not an IP address -- also the number of classes, must be last entry
+ IP_SCOPE_LINK_LOCAL = 1, // 169.254.x.x, IPv6 LL
+ IP_SCOPE_PRIVATE = 2, // 10.x.x.x, etc.
+ IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IP blocks often "bogarted"
+ IP_SCOPE_SHARED = 4, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT
+ IP_SCOPE_GLOBAL = 5, // globally routable IP address (all others)
+ IP_SCOPE_LOOPBACK = 6, // 127.0.0.1
+ IP_SCOPE_MULTICAST = 7 // 224.0.0.0 and other multicast IPs
};
InetAddress() throw() { memset(this,0,sizeof(InetAddress)); }
diff --git a/node/Path.hpp b/node/Path.hpp
index a5ee6aa9..7837ba4e 100644
--- a/node/Path.hpp
+++ b/node/Path.hpp
@@ -145,7 +145,7 @@ public:
inline bool active(uint64_t now) const
throw()
{
- return ( (_fixed) || ((now - _lastReceived) < ZT_PEER_PATH_ACTIVITY_TIMEOUT) );
+ return ( (_fixed) || ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT) );
}
/**
diff --git a/node/Peer.cpp b/node/Peer.cpp
index debb4533..beaa9d3b 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -192,6 +192,34 @@ void Peer::clearPaths(bool fixedToo)
}
}
+void Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope scope,uint64_t now)
+{
+ unsigned int np = _numPaths;
+ unsigned int x = 0;
+ unsigned int y = 0;
+ while (x < np) {
+ if (_paths[x].address().ipScope() == scope) {
+ if (_paths[x].fixed()) {
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_NOP);
+ outp.armor(_key,false);
+ RR->node->putPacket(_paths[x].address(),outp.data(),outp.size(),_paths[x].desperation(now));
+ _paths[y++] = _paths[x]; // keep fixed paths
+ }
+ } else {
+ _paths[y++] = _paths[x]; // keep paths not in this scope
+ }
+ ++x;
+ }
+ _numPaths = y;
+
+ if ((y < np)&&(alive(now))) {
+ // Try to re-establish direct connectivity to this peer if it's alive
+ // and we have forgotten paths to it.
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_NOP);
+ RR->sw->send(outp,true);
+ }
+}
+
void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
{
uint64_t bestV4 = 0,bestV6 = 0;
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 147ce571..31964c39 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -230,10 +230,9 @@ public:
inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; }
/**
- * @param now Current time
- * @return True if peer has received something within ZT_PEER_ACTIVITY_TIMEOUT ms
+ * @return True if peer has received an actual data frame within ZT_PEER_ACTIVITY_TIMEOUT milliseconds
*/
- inline bool alive(uint64_t now) const throw() { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
+ inline uint64_t alive(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); }
/**
* @return Current latency or 0 if unknown (max: 65535)
@@ -293,6 +292,20 @@ public:
void clearPaths(bool fixedToo);
/**
+ * Reset paths within a given scope
+ *
+ * For fixed paths in this scope, a packet is sent. Non-fixed paths in this
+ * scope are forgotten. If there are no paths remaining, a message is sent
+ * indirectly to reestablish connectivity if we're actively exchanging
+ * data with this peer (alive).
+ *
+ * @param RR Runtime environment
+ * @param scope IP scope of paths to reset
+ * @param now Current time
+ */
+ void resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope scope,uint64_t now);
+
+ /**
* @return 256-bit secret symmetric encryption key
*/
inline const unsigned char *key() const throw() { return _key; }
diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp
index c8b700a0..74c9f182 100644
--- a/node/SelfAwareness.cpp
+++ b/node/SelfAwareness.cpp
@@ -25,6 +25,10 @@
* LLC. Start here: http://www.zerotier.com/
*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "Constants.hpp"
#include "SelfAwareness.hpp"
#include "RuntimeEnvironment.hpp"
@@ -35,17 +39,52 @@
namespace ZeroTier {
+class _ResetWithinScope
+{
+public:
+ _ResetWithinScope(const RuntimeEnvironment *renv,uint64_t now,InetAddress::IpScope scope) :
+ RR(renv),
+ _now(now),
+ _scope(scope) {}
+ inline void operator()(Topology &t,const SharedPtr<Peer> &p) { p->resetWithinScope(RR,_scope,_now); }
+private:
+ const RuntimeEnvironment *RR;
+ uint64_t _now;
+ InetAddress::IpScope _scope;
+};
+
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
RR(renv)
{
+ memset(_lastPhysicalAddress,0,sizeof(_lastPhysicalAddress));
}
SelfAwareness::~SelfAwareness()
{
}
-void SelfAwareness::iam(const InetAddress &physicalAddress,bool trusted)
+void SelfAwareness::iam(const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted)
{
+ const unsigned int scope = (unsigned int)myPhysicalAddress.ipScope();
+
+ // This code depends on the numeric values assigned to scopes in InetAddress.hpp
+ if ((scope > 0)&&(scope < (unsigned int)InetAddress::IP_SCOPE_LOOPBACK)) {
+ /* For now only trusted peers are permitted to inform us of changes to
+ * our global Internet IP or to changes of NATed IPs. We'll let peers on
+ * private, shared, or link-local networks inform us of changes as long
+ * as they too are at the same scope. This discrimination avoids a DoS
+ * attack in which an attacker could force us to reset our connections. */
+ if ( (!trusted) && ((scope == (unsigned int)InetAddress::IP_SCOPE_GLOBAL)||(scope != (unsigned int)reporterPhysicalAddress.ipScope())) )
+ return;
+
+ InetAddress &lastPhy = _lastPhysicalAddress[scope - 1];
+ if ((lastPhy)&&(lastPhy != myPhysicalAddress)) {
+ lastPhy = myPhysicalAddress;
+ _ResetWithinScope rset(RR,RR->node->now(),(InetAddress::IpScope)scope);
+ RR->topology->eachPeer<_ResetWithinScope &>(rset);
+ }
+ }
+
Mutex::Lock _l(_lock);
}
diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp
index 6d0b9ebb..eadc2149 100644
--- a/node/SelfAwareness.hpp
+++ b/node/SelfAwareness.hpp
@@ -47,14 +47,16 @@ public:
/**
* Called when a trusted remote peer informs us of our external network address
*
- * @param physicalAddress Physical address as reflected by any trusted peer
- * @param trusted True if this peer is trusted
+ * @param reporterPhysicalAddress Physical address that reporting peer seems to have
+ * @param myPhysicalAddress Physical address that peer says we have
+ * @param trusted True if this peer is trusted as an authority to inform us of external address changes
*/
- void iam(const InetAddress &physicalAddress,bool trusted);
+ void iam(const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted);
private:
const RuntimeEnvironment *RR;
Mutex _lock;
+ InetAddress _lastPhysicalAddress[5]; // 5 == the number of address classes we care about, see InetAddress.hpp and SelfAwareness.cpp
};
} // namespace ZeroTier
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 8b3d2e71..295c3c8a 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -253,36 +253,6 @@ void Topology::clean(uint64_t now)
}
}
-/*
-bool Topology::updateSurface(const SharedPtr<Peer> &remotePeer,const InetAddress &mirroredAddress,uint64_t now)
-{
- Mutex::Lock _l(_lock);
-
- if (std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),remotePeer->address()) == _supernodeAddresses.end())
- return false;
-
- if (_surface.update(mirroredAddress)) {
- // Clear non-fixed paths for all peers -- will force reconnect on next activity
- for(std::map< Address,SharedPtr<Peer> >::const_iterator ap(_activePeers.begin());ap!=_activePeers.end();++ap)
- ap->second->clearPaths(false);
-
- // Reset TCP tunneling if our global addressing has changed
- if (!mirroredAddress.isLinkLocal())
- (const_cast <RuntimeEnvironment *>(RR))->tcpTunnelingEnabled = false;
-
- // Ping supernodes now (other than the one we might have just heard from)
- for(std::vector< SharedPtr<Peer> >::const_iterator sn(_supernodePeers.begin());sn!=_supernodePeers.end();++sn) {
- if (remotePeer != *sn)
- (*sn)->sendPing(RR,now);
- }
-
- return true;
- }
-
- return false;
-}
-*/
-
bool Topology::authenticateRootTopology(const Dictionary &rt)
{
try {
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 6dee11bc..d099d93b 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -280,44 +280,6 @@ public:
uint64_t _now;
const RuntimeEnvironment *RR;
};
-
- /**
- * Function object to forget direct links to active peers and then ping them indirectly
- */
- class ResetActivePeers
- {
- public:
- ResetActivePeers(const RuntimeEnvironment *renv,uint64_t now) throw() :
- _now(now),
- _supernode(renv->topology->getBestSupernode()),
- _supernodeAddresses(renv->topology->supernodeAddresses()),
- RR(renv) {}
-
- inline void operator()(Topology &t,const SharedPtr<Peer> &p)
- {
- p->clearPaths(false); // false means don't forget 'fixed' paths e.g. supernodes
-
- Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP);
- outp.armor(p->key(),false); // no need to encrypt a NOP
-
- if (std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),p->address()) != _supernodeAddresses.end()) {
- // Send NOP directly to supernodes
- p->send(RR,outp.data(),outp.size(),_now);
- } else {
- // Send NOP indirectly to regular peers if still active, triggering a new RENDEZVOUS
- if (((_now - p->lastFrame()) < ZT_PEER_PATH_ACTIVITY_TIMEOUT)&&(_supernode)) {
- TRACE("sending reset NOP to %s",p->address().toString().c_str());
- _supernode->send(RR,outp.data(),outp.size(),_now);
- }
- }
- }
-
- private:
- uint64_t _now;
- SharedPtr<Peer> _supernode;
- std::vector<Address> _supernodeAddresses;
- const RuntimeEnvironment *RR;
- };
#endif
/**