mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 04:57:53 +00:00
Implemented empirical determination of external addressing, paritioned per scope.
This commit is contained in:
parent
817824b88b
commit
52c3b7c34e
@ -301,11 +301,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
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -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)); }
|
||||
|
@ -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) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
@ -292,6 +291,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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user