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"
2014-04-10 21:22:25 +00:00
# include "AntiRecursion.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 ;
2013-07-04 20:56:19 +00:00
Peer : : Peer ( const Identity & myIdentity , const Identity & peerIdentity )
throw ( std : : runtime_error ) :
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-04-15 20:15:09 +00:00
_lastPathConfirmationSent ( 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 (
2014-09-24 20:53:03 +00:00
const RuntimeEnvironment * RR ,
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-10-27 21:37:38 +00:00
InetAddress redirectTo ;
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.
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 - > antiRec - > logOutgoingZT ( outp . data ( ) , outp . size ( ) ) ;
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 - > antiRec - > logOutgoingZT ( outp . data ( ) , outp . size ( ) ) ;
RR - > node - > putPacket ( localAddr , remoteAddr , outp . data ( ) , outp . size ( ) ) ;
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-21 00:36:10 +00:00
bool pathIsConfirmed = 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 ;
# ifdef ZT_ENABLE_CLUSTER
2015-10-27 23:47:13 +00:00
// If we think this peer belongs elsewhere, don't learn this path or
// do other connection init stuff.
if ( redirectTo )
2015-10-27 16:36:48 +00:00
return ;
# endif
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 ) {
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 ) ;
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
2015-10-27 00:58:51 +00:00
if ( ! pathIsConfirmed ) {
2015-10-27 22:57:26 +00:00
if ( ( verb = = Packet : : VERB_OK ) | | ( RR - > topology - > amRoot ( ) ) ) {
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 ) {
if ( _paths [ p ] . lastReceived ( ) < = slotLRmin ) {
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 ) ;
_numPaths = np ;
pathIsConfirmed = true ;
_sortPaths ( now ) ;
}
2015-10-01 18:11:52 +00:00
2015-10-27 00:58:51 +00:00
} else {
/* If this path is not known, send a HELLO. We don't learn
* paths without confirming that a bidirectional link is in
* fact present , but any packet that decodes and authenticates
* correctly is considered valid . */
if ( ( now - _lastPathConfirmationSent ) > = ZT_MIN_PATH_CONFIRMATION_INTERVAL ) {
_lastPathConfirmationSent = now ;
TRACE ( " got %s via unknown path %s(%s), confirming... " , Packet : : verbString ( verb ) , _id . address ( ) . toString ( ) . c_str ( ) , remoteAddr . toString ( ) . c_str ( ) ) ;
attemptToContactAt ( RR , 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-21 00:36:10 +00:00
# ifdef ZT_ENABLE_CLUSTER
2015-10-27 00:58:51 +00:00
if ( ( RR - > cluster ) & & ( pathIsConfirmed ) )
2015-10-27 23:47:13 +00:00
RR - > cluster - > replicateHavePeer ( _id , remoteAddr ) ;
2015-10-21 00:36:10 +00:00
# endif
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
}
2015-09-24 23:21:36 +00:00
void Peer : : attemptToContactAt ( const RuntimeEnvironment * RR , const InetAddress & localAddr , const InetAddress & atAddress , uint64_t now )
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-10-07 18:57:59 +00:00
RR - > antiRec - > logOutgoingZT ( outp . data ( ) , outp . size ( ) ) ;
2015-09-24 23:21:36 +00:00
RR - > node - > putPacket ( localAddr , atAddress , outp . data ( ) , outp . size ( ) ) ;
2015-04-07 19:22:33 +00:00
}
2015-10-16 17:10:12 +00:00
bool Peer : : doPingAndKeepalive ( const RuntimeEnvironment * RR , 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());
2015-10-16 17:10:12 +00:00
attemptToContactAt ( RR , p - > localAddress ( ) , p - > address ( ) , now ) ;
p - > sent ( now ) ;
} else if ( ( ( now - p - > lastSend ( ) ) > = 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 ) ) ;
p - > sent ( 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
}
2015-10-27 22:00:16 +00:00
void Peer : : pushDirectPaths ( const RuntimeEnvironment * RR , 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 ;
}
uint8_t flags = 0 ;
2015-10-27 22:00:16 +00:00
/* TODO: path trust is not implemented yet
2015-07-13 17:03:04 +00:00
switch ( p - > trust ( ) ) {
default :
break ;
case Path : : TRUST_PRIVACY :
flags | = 0x04 ; // no encryption
break ;
case Path : : TRUST_ULTIMATE :
flags | = ( 0x04 | 0x08 ) ; // no encryption, no authentication (redundant but go ahead and set both)
break ;
2015-07-06 21:39:28 +00:00
}
2015-10-27 22:00:16 +00:00
*/
2015-07-06 21:39:28 +00:00
outp . append ( 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
2015-05-01 04:09:41 +00:00
bool Peer : : resetWithinScope ( const RuntimeEnvironment * RR , 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 ) {
2015-10-13 19:10:44 +00:00
attemptToContactAt ( RR , _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-10-01 18:11:52 +00:00
_sortPaths ( now ) ;
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 ;
}
bool Peer : : validateAndSetNetworkMembershipCertificate ( const RuntimeEnvironment * RR , uint64_t nwid , const CertificateOfMembership & com )
{
// Sanity checks
if ( ( ! com ) | | ( com . issuedTo ( ) ! = _id . address ( ) ) )
return false ;
// Return true if we already have this *exact* COM
{
Mutex : : Lock _l ( _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
}
void Peer : : clean ( const RuntimeEnvironment * RR , uint64_t now )
{
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 ) ;
}
}
}
2015-10-01 19:25:43 +00:00
struct _SortPathsByQuality
{
uint64_t _now ;
_SortPathsByQuality ( const uint64_t now ) : _now ( now ) { }
2015-10-27 22:00:16 +00:00
inline bool operator ( ) ( const Path & a , const Path & b ) const
2015-10-01 19:25:43 +00:00
{
const uint64_t qa = (
( ( uint64_t ) a . active ( _now ) < < 63 ) |
( ( ( uint64_t ) ( a . preferenceRank ( ) & 0xfff ) ) < < 51 ) |
( ( uint64_t ) a . lastReceived ( ) & 0x7ffffffffffffULL ) ) ;
const uint64_t qb = (
( ( uint64_t ) b . active ( _now ) < < 63 ) |
( ( ( uint64_t ) ( b . preferenceRank ( ) & 0xfff ) ) < < 51 ) |
( ( uint64_t ) b . lastReceived ( ) & 0x7ffffffffffffULL ) ) ;
return ( qb < qa ) ; // invert sense to sort in descending order
}
} ;
2015-10-01 18:11:52 +00:00
void Peer : : _sortPaths ( const uint64_t now )
{
// assumes _lock is locked
_lastPathSort = now ;
std : : sort ( & ( _paths [ 0 ] ) , & ( _paths [ _numPaths ] ) , _SortPathsByQuality ( now ) ) ;
}
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
if ( ( now - _lastPathSort ) > = ZT_PEER_PATH_SORT_INTERVAL )
_sortPaths ( now ) ;
if ( _paths [ 0 ] . active ( now ) ) {
return & ( _paths [ 0 ] ) ;
} else {
_sortPaths ( now ) ;
if ( _paths [ 0 ] . active ( now ) )
return & ( _paths [ 0 ] ) ;
}
2015-10-27 22:00:16 +00:00
return ( Path * ) 0 ;
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
if ( ( now - _lastPathSort ) > = ZT_PEER_PATH_SORT_INTERVAL )
_sortPaths ( now ) ;
for ( int k = 0 ; k < 2 ; + + k ) { // try once, and if it fails sort and try one more time
for ( unsigned int i = 0 ; i < _numPaths ; + + i ) {
if ( ( _paths [ i ] . active ( now ) ) & & ( ( int ) _paths [ i ] . address ( ) . ss_family = = inetAddressFamily ) )
return & ( _paths [ i ] ) ;
}
_sortPaths ( now ) ;
}
2015-10-27 22:00:16 +00:00
return ( Path * ) 0 ;
2015-10-16 17:10:12 +00:00
}
2013-07-04 20:56:19 +00:00
} // namespace ZeroTier