2013-07-04 20:56:19 +00:00
/*
2015-02-17 21:11:34 +00:00
* ZeroTier One - Network Virtualization Everywhere
* Copyright ( C ) 2011 - 2015 ZeroTier , Inc .
2013-07-04 20:56:19 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* - -
*
* ZeroTier may be used and distributed under the terms of the GPLv3 , which
* are available at : http : //www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form , please contact ZeroTier Networks
* LLC . Start here : http : //www.zerotier.com/
*/
2015-04-07 19:22:33 +00:00
# include "../version.h"
2014-08-05 21:05:50 +00:00
# include "Constants.hpp"
2013-07-04 20:56:19 +00:00
# include "Peer.hpp"
2015-04-03 00:54:56 +00:00
# include "Node.hpp"
2013-10-01 20:01:36 +00:00
# include "Switch.hpp"
2014-09-30 15:38:03 +00:00
# include "Network.hpp"
2015-07-28 00:02:43 +00:00
# include "SelfAwareness.hpp"
2015-10-20 23:24:21 +00:00
# include "Cluster.hpp"
2015-10-27 16:36:48 +00:00
# include "Packet.hpp"
2013-07-04 20:56:19 +00:00
2013-12-24 18:39:29 +00:00
# include <algorithm>
2015-10-01 18:11:52 +00:00
# define ZT_PEER_PATH_SORT_INTERVAL 5000
2013-07-04 20:56:19 +00:00
namespace ZeroTier {
2015-09-22 22:58:00 +00:00
// Used to send varying values for NAT keepalive
static uint32_t _natKeepaliveBuf = 0 ;
2016-01-06 00:41:54 +00:00
Peer : : Peer ( const RuntimeEnvironment * renv , const Identity & myIdentity , const Identity & peerIdentity ) :
RR ( renv ) ,
2013-10-21 14:29:44 +00:00
_lastUsed ( 0 ) ,
2014-06-30 18:31:04 +00:00
_lastReceive ( 0 ) ,
2013-07-13 18:28:26 +00:00
_lastUnicastFrame ( 0 ) ,
_lastMulticastFrame ( 0 ) ,
2014-10-13 21:12:51 +00:00
_lastAnnouncedTo ( 0 ) ,
2015-10-16 17:28:09 +00:00
_lastDirectPathPushSent ( 0 ) ,
2015-10-28 01:18:26 +00:00
_lastDirectPathPushReceive ( 0 ) ,
2015-10-01 18:11:52 +00:00
_lastPathSort ( 0 ) ,
2015-10-16 17:58:59 +00:00
_vProto ( 0 ) ,
2013-07-12 02:06:25 +00:00
_vMajor ( 0 ) ,
_vMinor ( 0 ) ,
2014-02-03 18:46:37 +00:00
_vRevision ( 0 ) ,
2015-04-03 00:54:56 +00:00
_id ( peerIdentity ) ,
2014-10-21 17:42:04 +00:00
_numPaths ( 0 ) ,
2015-10-01 18:11:52 +00:00
_latency ( 0 ) ,
2015-10-28 01:18:26 +00:00
_directPathPushCutoffCount ( 0 ) ,
2015-10-01 18:11:52 +00:00
_networkComs ( 4 ) ,
_lastPushedComs ( 4 )
2013-07-04 20:56:19 +00:00
{
2013-10-05 14:19:12 +00:00
if ( ! myIdentity . agree ( peerIdentity , _key , ZT_PEER_SECRET_KEY_LENGTH ) )
2013-07-04 20:56:19 +00:00
throw std : : runtime_error ( " new peer identity key agreement failed " ) ;
}
2014-10-21 17:42:04 +00:00
void Peer : : received (
2015-09-24 23:21:36 +00:00
const InetAddress & localAddr ,
2013-12-24 18:39:29 +00:00
const InetAddress & remoteAddr ,
unsigned int hops ,
uint64_t packetId ,
Packet : : Verb verb ,
uint64_t inRePacketId ,
2015-04-03 00:54:56 +00:00
Packet : : Verb inReVerb )
2013-07-04 20:56:19 +00:00
{
2015-10-27 00:58:51 +00:00
# ifdef ZT_ENABLE_CLUSTER
2015-11-09 22:25:28 +00:00
bool suboptimalPath = false ;
2015-10-27 21:37:38 +00:00
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.
2015-11-03 19:18:45 +00:00
InetAddress redirectTo ;
2015-10-27 21:37:38 +00:00
if ( ( RR - > cluster - > findBetterEndpoint ( redirectTo , _id . address ( ) , remoteAddr , false ) ) & & ( verb ! = Packet : : VERB_OK ) & & ( verb ! = Packet : : VERB_ERROR ) & & ( verb ! = Packet : : VERB_RENDEZVOUS ) & & ( verb ! = Packet : : VERB_PUSH_DIRECT_PATHS ) ) {
2015-10-27 22:57:26 +00:00
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 ) 0 ) ; // no flags
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 ) ;
2015-10-27 16:53:43 +00:00
} else {
2015-10-27 22:57:26 +00:00
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 ) ;
RR - > node - > putPacket ( localAddr , remoteAddr , outp . data ( ) , outp . size ( ) ) ;
} 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 ) ;
2015-10-27 16:53:43 +00:00
}
2015-10-27 22:57:26 +00:00
outp . armor ( _key , true ) ;
RR - > node - > putPacket ( localAddr , remoteAddr , outp . data ( ) , outp . size ( ) ) ;
2015-10-27 16:36:48 +00:00
}
2015-11-09 22:25:28 +00:00
suboptimalPath = true ;
2015-10-27 16:36:48 +00:00
}
2015-10-27 00:58:51 +00:00
}
# endif
2015-04-03 00:54:56 +00:00
const uint64_t now = RR - > node - > now ( ) ;
2015-10-01 18:37:02 +00:00
bool needMulticastGroupAnnounce = false ;
2015-10-01 18:11:52 +00:00
2015-10-27 00:58:51 +00:00
{ // begin _lock
2015-10-01 18:37:02 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-06-30 18:31:04 +00:00
2015-10-01 18:37:02 +00:00
_lastReceive = now ;
2015-10-27 16:36:48 +00:00
if ( ( verb = = Packet : : VERB_FRAME ) | | ( verb = = Packet : : VERB_EXT_FRAME ) )
_lastUnicastFrame = now ;
else if ( verb = = Packet : : VERB_MULTICAST_FRAME )
_lastMulticastFrame = now ;
if ( ( now - _lastAnnouncedTo ) > = ( ( ZT_MULTICAST_LIKE_EXPIRE / 2 ) - 1000 ) ) {
_lastAnnouncedTo = now ;
needMulticastGroupAnnounce = true ;
}
2015-04-07 19:22:33 +00:00
2015-10-27 00:58:51 +00:00
if ( hops = = 0 ) {
2015-12-22 00:15:39 +00:00
bool pathIsConfirmed = false ;
2015-10-27 00:58:51 +00:00
unsigned int np = _numPaths ;
for ( unsigned int p = 0 ; p < np ; + + p ) {
if ( ( _paths [ p ] . address ( ) = = remoteAddr ) & & ( _paths [ p ] . localAddress ( ) = = localAddr ) ) {
_paths [ p ] . received ( now ) ;
2015-11-09 22:25:28 +00:00
# ifdef ZT_ENABLE_CLUSTER
_paths [ p ] . setClusterSuboptimal ( suboptimalPath ) ;
# endif
2015-10-27 00:58:51 +00:00
pathIsConfirmed = true ;
break ;
2015-10-01 18:37:02 +00:00
}
2015-10-27 00:58:51 +00:00
}
2015-10-01 18:11:52 +00:00
2016-01-11 18:17:44 +00:00
if ( ( ! pathIsConfirmed ) & & ( RR - > node - > shouldUsePathForZeroTierTraffic ( localAddr , remoteAddr ) ) ) {
2015-11-07 00:12:41 +00:00
if ( verb = = Packet : : VERB_OK ) {
2015-10-01 18:37:02 +00:00
2015-10-27 22:00:16 +00:00
Path * slot = ( Path * ) 0 ;
2015-10-27 00:58:51 +00:00
if ( np < ZT_MAX_PEER_NETWORK_PATHS ) {
slot = & ( _paths [ np + + ] ) ;
2015-10-01 18:37:02 +00:00
} else {
2015-10-27 00:58:51 +00:00
uint64_t slotLRmin = 0xffffffffffffffffULL ;
for ( unsigned int p = 0 ; p < ZT_MAX_PEER_NETWORK_PATHS ; + + p ) {
2016-01-06 18:00:03 +00:00
if ( ! _paths [ p ] . active ( now ) ) {
slot = & ( _paths [ p ] ) ;
break ;
} else if ( _paths [ p ] . lastReceived ( ) < = slotLRmin ) {
2015-10-27 00:58:51 +00:00
slotLRmin = _paths [ p ] . lastReceived ( ) ;
slot = & ( _paths [ p ] ) ;
}
2015-10-01 18:37:02 +00:00
}
2015-10-27 00:58:51 +00:00
}
if ( slot ) {
2015-10-29 16:42:15 +00:00
* slot = Path ( localAddr , remoteAddr ) ;
2015-10-27 00:58:51 +00:00
slot - > received ( now ) ;
2015-11-09 22:25:28 +00:00
# ifdef ZT_ENABLE_CLUSTER
slot - > setClusterSuboptimal ( suboptimalPath ) ;
# endif
2015-10-27 00:58:51 +00:00
_numPaths = np ;
}
2015-10-01 18:11:52 +00:00
2015-11-10 02:01:23 +00:00
# ifdef ZT_ENABLE_CLUSTER
2015-11-11 22:36:22 +00:00
if ( RR - > cluster )
2015-11-10 02:01:23 +00:00
RR - > cluster - > broadcastHavePeer ( _id ) ;
# endif
2015-10-27 00:58:51 +00:00
} else {
2015-12-22 00:15:39 +00:00
TRACE ( " got %s via unknown path %s(%s), confirming... " , Packet : : verbString ( verb ) , _id . address ( ) . toString ( ) . c_str ( ) , remoteAddr . toString ( ) . c_str ( ) ) ;
if ( ( _vProto > = 5 ) & & ( ! ( ( _vMajor = = 1 ) & & ( _vMinor = = 1 ) & & ( _vRevision = = 0 ) ) ) ) {
// 1.1.1 and newer nodes support ECHO, which is smaller -- but 1.1.0 has a bug so use HELLO there too
Packet outp ( _id . address ( ) , RR - > identity . address ( ) , Packet : : VERB_ECHO ) ;
outp . armor ( _key , true ) ;
RR - > node - > putPacket ( localAddr , remoteAddr , outp . data ( ) , outp . size ( ) ) ;
} else {
2016-01-06 00:41:54 +00:00
sendHELLO ( localAddr , remoteAddr , now ) ;
2015-04-15 20:15:09 +00:00
}
2015-10-27 00:58:51 +00:00
2014-04-01 05:23:55 +00:00
}
2014-03-21 21:31:10 +00:00
}
2014-03-21 03:07:35 +00:00
}
2015-10-27 00:58:51 +00:00
} // end _lock
2013-07-04 20:56:19 +00:00
2015-10-01 18:37:02 +00:00
if ( needMulticastGroupAnnounce ) {
const std : : vector < SharedPtr < Network > > networks ( RR - > node - > allNetworks ( ) ) ;
for ( std : : vector < SharedPtr < Network > > : : const_iterator n ( networks . begin ( ) ) ; n ! = networks . end ( ) ; + + n )
( * n ) - > tryAnnounceMulticastGroupsTo ( SharedPtr < Peer > ( this ) ) ;
}
2013-07-04 20:56:19 +00:00
}
2016-01-06 00:41:54 +00:00
void Peer : : sendHELLO ( const InetAddress & localAddr , const InetAddress & atAddress , uint64_t now , unsigned int ttl )
2015-04-07 19:22:33 +00:00
{
2015-10-01 18:11:52 +00:00
// _lock not required here since _id is immutable and nothing else is accessed
2015-04-07 19:22:33 +00:00
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 ) ;
outp . append ( ( uint16_t ) ZEROTIER_ONE_VERSION_REVISION ) ;
outp . append ( now ) ;
RR - > identity . serialize ( outp , false ) ;
2015-10-07 17:30:47 +00:00
atAddress . serialize ( outp ) ;
2015-10-13 19:10:44 +00:00
outp . append ( ( uint64_t ) RR - > topology - > worldId ( ) ) ;
outp . append ( ( uint64_t ) RR - > topology - > worldTimestamp ( ) ) ;
2015-04-07 19:22:33 +00:00
outp . armor ( _key , false ) ; // HELLO is sent in the clear
2015-11-09 23:44:13 +00:00
RR - > node - > putPacket ( localAddr , atAddress , outp . data ( ) , outp . size ( ) , ttl ) ;
2015-04-07 19:22:33 +00:00
}
2016-01-06 00:41:54 +00:00
bool Peer : : doPingAndKeepalive ( uint64_t now , int inetAddressFamily )
2015-04-08 02:31:11 +00:00
{
2015-10-27 22:00:16 +00:00
Path * p = ( Path * ) 0 ;
2015-10-16 17:10:12 +00:00
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2015-10-16 17:10:12 +00:00
if ( inetAddressFamily ! = 0 ) {
p = _getBestPath ( now , inetAddressFamily ) ;
} else {
p = _getBestPath ( now ) ;
}
if ( p ) {
if ( ( now - p - > lastReceived ( ) ) > = ZT_PEER_DIRECT_PING_DELAY ) {
2015-10-26 23:55:55 +00:00
//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());
2016-01-06 00:41:54 +00:00
sendHELLO ( p - > localAddress ( ) , p - > address ( ) , now ) ;
2015-10-16 17:10:12 +00:00
p - > sent ( now ) ;
2016-01-06 18:00:03 +00:00
p - > pinged ( now ) ;
2016-01-06 18:59:39 +00:00
} else if ( ( ( now - std : : max ( p - > lastSend ( ) , p - > lastKeepalive ( ) ) ) > = ZT_NAT_KEEPALIVE_DELAY ) & & ( ! p - > reliable ( ) ) ) {
2015-10-26 23:55:55 +00:00
//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());
2015-09-23 17:27:53 +00:00
_natKeepaliveBuf + = ( uint32_t ) ( ( now * 0x9e3779b1 ) > > 1 ) ; // tumble this around to send constantly varying (meaningless) payloads
2015-10-16 17:10:12 +00:00
RR - > node - > putPacket ( p - > localAddress ( ) , p - > address ( ) , & _natKeepaliveBuf , sizeof ( _natKeepaliveBuf ) ) ;
2016-01-06 18:00:03 +00:00
p - > sentKeepalive ( now ) ;
2015-10-19 22:03:58 +00:00
} else {
2015-10-26 23:55:55 +00:00
//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());
2015-04-08 02:31:11 +00:00
}
2015-10-16 17:10:12 +00:00
return true ;
2015-04-08 02:31:11 +00:00
}
2015-10-19 21:04:36 +00:00
2015-10-16 17:10:12 +00:00
return false ;
2015-04-08 02:31:11 +00:00
}
2016-01-06 00:41:54 +00:00
void Peer : : pushDirectPaths ( Path * path , uint64_t now , bool force )
2015-07-06 21:39:28 +00:00
{
2015-10-20 22:27:53 +00:00
# ifdef ZT_ENABLE_CLUSTER
// Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
if ( RR - > cluster )
return ;
# endif
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2015-10-16 17:28:09 +00:00
if ( ( ( now - _lastDirectPathPushSent ) > = ZT_DIRECT_PATH_PUSH_INTERVAL ) | | ( force ) ) {
_lastDirectPathPushSent = now ;
2015-07-06 21:39:28 +00:00
2015-10-27 22:00:16 +00:00
std : : vector < InetAddress > dps ( RR - > node - > directPaths ( ) ) ;
2015-10-07 18:57:59 +00:00
if ( dps . empty ( ) )
return ;
2015-07-28 00:02:43 +00:00
2015-07-13 17:35:33 +00:00
# ifdef ZT_TRACE
{
std : : string ps ;
2015-10-27 22:01:11 +00:00
for ( std : : vector < InetAddress > : : const_iterator p ( dps . begin ( ) ) ; p ! = dps . end ( ) ; + + p ) {
2015-07-13 17:35:33 +00:00
if ( ps . length ( ) > 0 )
ps . push_back ( ' , ' ) ;
2015-10-27 22:00:16 +00:00
ps . append ( p - > toString ( ) ) ;
2015-07-13 17:35:33 +00:00
}
2015-07-31 16:37:13 +00:00
TRACE ( " pushing %u direct paths to %s: %s " , ( unsigned int ) dps . size ( ) , _id . address ( ) . toString ( ) . c_str ( ) , ps . c_str ( ) ) ;
2015-07-13 17:35:33 +00:00
}
# endif
2015-07-06 22:28:48 +00:00
2015-10-27 22:00:16 +00:00
std : : vector < InetAddress > : : const_iterator p ( dps . begin ( ) ) ;
2015-07-06 21:39:28 +00:00
while ( p ! = dps . 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 ! = dps . end ( ) ) & & ( ( outp . size ( ) + 24 ) < ZT_PROTO_MAX_PACKET_LENGTH ) ) {
uint8_t addressType = 4 ;
2015-10-27 22:00:16 +00:00
switch ( p - > ss_family ) {
2015-07-06 21:39:28 +00:00
case AF_INET :
break ;
case AF_INET6 :
addressType = 6 ;
break ;
2015-07-13 17:03:04 +00:00
default : // we currently only push IP addresses
2015-07-06 21:39:28 +00:00
+ + p ;
continue ;
}
2015-12-22 00:15:39 +00:00
outp . append ( ( uint8_t ) 0 ) ; // no flags
2015-07-13 16:29:51 +00:00
outp . append ( ( uint16_t ) 0 ) ; // no extensions
2015-07-06 21:39:28 +00:00
outp . append ( addressType ) ;
2015-07-07 00:20:41 +00:00
outp . append ( ( uint8_t ) ( ( addressType = = 4 ) ? 6 : 18 ) ) ;
2015-10-27 22:00:16 +00:00
outp . append ( p - > rawIpData ( ) , ( ( addressType = = 4 ) ? 4 : 16 ) ) ;
outp . append ( ( uint16_t ) p - > port ( ) ) ;
2015-07-06 21:39:28 +00:00
+ + count ;
+ + p ;
}
if ( count ) {
outp . setAt ( ZT_PACKET_IDX_PAYLOAD , ( uint16_t ) count ) ;
2015-07-07 17:00:34 +00:00
outp . armor ( _key , true ) ;
path - > send ( RR , outp . data ( ) , outp . size ( ) , now ) ;
2015-07-06 21:39:28 +00:00
}
}
}
}
2015-07-06 21:08:13 +00:00
2016-01-06 00:41:54 +00:00
bool Peer : : resetWithinScope ( InetAddress : : IpScope scope , uint64_t now )
2015-04-07 18:56:10 +00:00
{
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2015-04-07 18:56:10 +00:00
unsigned int np = _numPaths ;
unsigned int x = 0 ;
unsigned int y = 0 ;
while ( x < np ) {
if ( _paths [ x ] . address ( ) . ipScope ( ) = = scope ) {
2016-01-06 18:00:03 +00:00
// Resetting a path means sending a HELLO and then forgetting it. If we
// get OK(HELLO) then it will be re-learned.
2016-01-06 00:41:54 +00:00
sendHELLO ( _paths [ x ] . localAddress ( ) , _paths [ x ] . address ( ) , now ) ;
2015-04-07 18:56:10 +00:00
} else {
2015-10-13 19:10:44 +00:00
_paths [ y + + ] = _paths [ x ] ;
2015-04-07 18:56:10 +00:00
}
+ + x ;
}
_numPaths = y ;
2015-05-01 04:09:41 +00:00
return ( y < np ) ;
2015-04-07 18:56:10 +00:00
}
2015-05-21 22:58:26 +00:00
void Peer : : getBestActiveAddresses ( uint64_t now , InetAddress & v4 , InetAddress & v6 ) const
2014-04-09 23:00:25 +00:00
{
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-04-09 23:00:25 +00:00
uint64_t bestV4 = 0 , bestV6 = 0 ;
2014-10-21 17:42:04 +00:00
for ( unsigned int p = 0 , np = _numPaths ; p < np ; + + p ) {
2015-05-21 22:58:26 +00:00
if ( _paths [ p ] . active ( now ) ) {
2014-10-21 17:42:04 +00:00
uint64_t lr = _paths [ p ] . lastReceived ( ) ;
2014-04-09 23:00:25 +00:00
if ( lr ) {
2014-10-21 17:42:04 +00:00
if ( _paths [ p ] . address ( ) . isV4 ( ) ) {
2014-04-09 23:00:25 +00:00
if ( lr > = bestV4 ) {
bestV4 = lr ;
2014-10-21 17:42:04 +00:00
v4 = _paths [ p ] . address ( ) ;
2014-04-09 23:00:25 +00:00
}
2014-10-21 17:42:04 +00:00
} else if ( _paths [ p ] . address ( ) . isV6 ( ) ) {
2014-04-09 23:00:25 +00:00
if ( lr > = bestV6 ) {
bestV6 = lr ;
2014-10-21 17:42:04 +00:00
v6 = _paths [ p ] . address ( ) ;
2014-04-09 23:00:25 +00:00
}
}
}
}
}
}
2015-10-01 18:11:52 +00:00
bool Peer : : networkMembershipCertificatesAgree ( uint64_t nwid , const CertificateOfMembership & com ) const
{
Mutex : : Lock _l ( _lock ) ;
const _NetworkCom * ourCom = _networkComs . get ( nwid ) ;
if ( ourCom )
return ourCom - > com . agreesWith ( com ) ;
return false ;
}
2016-01-06 00:41:54 +00:00
bool Peer : : validateAndSetNetworkMembershipCertificate ( uint64_t nwid , const CertificateOfMembership & com )
2015-10-01 18:11:52 +00:00
{
// Sanity checks
if ( ( ! com ) | | ( com . issuedTo ( ) ! = _id . address ( ) ) )
return false ;
// Return true if we already have this *exact* COM
{
Mutex : : Lock _l ( _lock ) ;
_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 ) ) {
2015-10-03 02:39:13 +00:00
TRACE ( " rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network " , ( unsigned long long ) _id , com . signedBy ( ) . toString ( ) . c_str ( ) ) ;
2015-10-01 18:11:52 +00:00
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 ) ) {
2015-10-03 02:39:13 +00:00
TRACE ( " rejected network membership certificate for %.16llx self signed by %s: signature check failed " , ( unsigned long long ) _id , com . signedBy ( ) . toString ( ) . c_str ( ) ) ;
2015-10-01 18:11:52 +00:00
return false ; // invalid signature
}
} else {
SharedPtr < Peer > 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 ( ) ) ) {
2015-10-03 02:39:13 +00:00
TRACE ( " rejected network membership certificate for %.16llx signed by %s: signature check failed " , ( unsigned long long ) _id , com . signedBy ( ) . toString ( ) . c_str ( ) ) ;
2015-10-01 18:11:52 +00:00
return false ; // invalid signature
}
}
// If we made it past all those checks, add or update cert in our cert info store
{
Mutex : : Lock _l ( _lock ) ;
_networkComs . set ( nwid , _NetworkCom ( RR - > node - > now ( ) , com ) ) ;
}
return true ;
}
bool Peer : : needsOurNetworkMembershipCertificate ( uint64_t nwid , uint64_t now , bool updateLastPushedTime )
{
Mutex : : Lock _l ( _lock ) ;
uint64_t & lastPushed = _lastPushedComs [ nwid ] ;
const uint64_t tmp = lastPushed ;
if ( updateLastPushedTime )
lastPushed = now ;
2015-10-01 20:01:18 +00:00
return ( ( now - tmp ) > = ( ZT_NETWORK_AUTOCONF_DELAY / 2 ) ) ;
2015-10-01 18:11:52 +00:00
}
2016-01-06 00:41:54 +00:00
void Peer : : clean ( uint64_t now )
2015-10-01 18:11:52 +00:00
{
Mutex : : Lock _l ( _lock ) ;
{
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 ;
}
{
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 ) ;
}
}
}
2016-01-06 00:41:54 +00:00
bool Peer : : _checkPath ( Path & p , const uint64_t now )
{
// assumes _lock is locked
if ( ! p . active ( now ) )
return false ;
2016-01-06 18:00:03 +00:00
/* 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 . */
2016-01-06 20:54:51 +00:00
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 ) & &
( ! RR - > topology - > amRoot ( ) )
) {
2016-01-06 18:59:39 +00:00
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 ( ) ) ;
2016-01-06 00:48:35 +00:00
if ( ( _vProto > = 5 ) & & ( ! ( ( _vMajor = = 1 ) & & ( _vMinor = = 1 ) & & ( _vRevision = = 0 ) ) ) ) {
// 1.1.1 and newer nodes support ECHO, which is smaller -- but 1.1.0 has a bug so use HELLO there too
Packet outp ( _id . address ( ) , RR - > identity . address ( ) , Packet : : VERB_ECHO ) ;
outp . armor ( _key , true ) ;
p . send ( RR , outp . data ( ) , outp . size ( ) , now ) ;
2016-01-06 18:00:03 +00:00
p . pinged ( now ) ;
2016-01-06 00:48:35 +00:00
} else {
sendHELLO ( p . localAddress ( ) , p . address ( ) , now ) ;
p . sent ( now ) ;
2016-01-06 18:00:03 +00:00
p . pinged ( now ) ;
2016-01-06 00:41:54 +00:00
}
2016-01-06 00:48:35 +00:00
p . increaseProbation ( ) ;
2016-01-06 00:41:54 +00:00
}
return true ;
}
2015-10-27 22:00:16 +00:00
Path * Peer : : _getBestPath ( const uint64_t now )
2015-10-01 18:11:52 +00:00
{
// assumes _lock is locked
2015-12-22 00:15:39 +00:00
Path * bestPath = ( Path * ) 0 ;
uint64_t bestPathScore = 0 ;
for ( unsigned int i = 0 ; i < _numPaths ; + + i ) {
const uint64_t score = _paths [ i ] . score ( ) ;
2016-01-06 00:41:54 +00:00
if ( ( score > = bestPathScore ) & & ( _checkPath ( _paths [ i ] , now ) ) ) {
2015-12-22 00:15:39 +00:00
bestPathScore = score ;
bestPath = & ( _paths [ i ] ) ;
}
2015-10-01 18:11:52 +00:00
}
2015-12-22 00:15:39 +00:00
return bestPath ;
2015-10-01 18:11:52 +00:00
}
2015-10-27 22:00:16 +00:00
Path * Peer : : _getBestPath ( const uint64_t now , int inetAddressFamily )
2015-10-16 17:10:12 +00:00
{
// assumes _lock is locked
2015-12-22 00:15:39 +00:00
Path * bestPath = ( Path * ) 0 ;
uint64_t bestPathScore = 0 ;
for ( unsigned int i = 0 ; i < _numPaths ; + + i ) {
const uint64_t score = _paths [ i ] . score ( ) ;
2016-01-06 00:41:54 +00:00
if ( ( ( int ) _paths [ i ] . address ( ) . ss_family = = inetAddressFamily ) & & ( score > = bestPathScore ) & & ( _checkPath ( _paths [ i ] , now ) ) ) {
2015-12-22 00:15:39 +00:00
bestPathScore = score ;
bestPath = & ( _paths [ i ] ) ;
2015-10-16 17:10:12 +00:00
}
}
2015-12-22 00:15:39 +00:00
return bestPath ;
2015-10-16 17:10:12 +00:00
}
2013-07-04 20:56:19 +00:00
} // namespace ZeroTier