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"
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-07-06 21:08:13 +00:00
_lastDirectPathPush ( 0 ) ,
2015-10-01 18:11:52 +00:00
_lastPathSort ( 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 ) ,
_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 " ) ;
}
2015-10-01 18:11:52 +00:00
struct _SortPathsByQuality
{
uint64_t _now ;
_SortPathsByQuality ( const uint64_t now ) : _now ( now ) { }
inline bool operator ( ) ( const RemotePath & a , const RemotePath & b ) const
{
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
}
} ;
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-04-03 00:54:56 +00:00
const uint64_t now = RR - > node - > now ( ) ;
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-06-30 18:31:04 +00:00
_lastReceive = now ;
2014-04-01 05:23:55 +00:00
if ( ! hops ) {
2015-04-07 19:22:33 +00:00
bool pathIsConfirmed = false ;
2015-04-03 00:54:56 +00:00
/* Learn new paths from direct (hops == 0) packets */
2014-03-21 21:31:10 +00:00
{
2015-04-03 00:54:56 +00:00
unsigned int np = _numPaths ;
for ( unsigned int p = 0 ; p < np ; + + p ) {
2015-09-24 23:21:36 +00:00
if ( ( _paths [ p ] . address ( ) = = remoteAddr ) & & ( _paths [ p ] . localAddress ( ) = = localAddr ) ) {
2015-05-21 22:58:26 +00:00
_paths [ p ] . received ( now ) ;
2015-04-07 19:22:33 +00:00
pathIsConfirmed = true ;
2014-03-21 21:31:10 +00:00
break ;
}
2014-03-21 03:07:35 +00:00
}
2015-04-07 19:22:33 +00:00
if ( ! pathIsConfirmed ) {
if ( ( verb = = Packet : : VERB_OK ) & & ( inReVerb = = Packet : : VERB_HELLO ) ) {
2015-10-01 18:11:52 +00:00
2015-04-07 19:22:33 +00:00
// Learn paths if they've been confirmed via a HELLO
2015-07-06 21:08:13 +00:00
RemotePath * slot = ( RemotePath * ) 0 ;
2015-09-24 23:21:36 +00:00
if ( np < ZT_MAX_PEER_NETWORK_PATHS ) {
2015-04-07 19:22:33 +00:00
// Add new path
slot = & ( _paths [ np + + ] ) ;
} else {
// Replace oldest non-fixed path
uint64_t slotLRmin = 0xffffffffffffffffULL ;
2015-09-24 23:21:36 +00:00
for ( unsigned int p = 0 ; p < ZT_MAX_PEER_NETWORK_PATHS ; + + p ) {
2015-04-07 19:22:33 +00:00
if ( ( ! _paths [ p ] . fixed ( ) ) & & ( _paths [ p ] . lastReceived ( ) < = slotLRmin ) ) {
slotLRmin = _paths [ p ] . lastReceived ( ) ;
slot = & ( _paths [ p ] ) ;
}
2015-04-03 00:54:56 +00:00
}
2014-10-21 17:42:04 +00:00
}
2015-04-07 19:22:33 +00:00
if ( slot ) {
2015-09-24 23:21:36 +00:00
* slot = RemotePath ( localAddr , remoteAddr , false ) ;
2015-05-21 22:58:26 +00:00
slot - > received ( now ) ;
2015-04-07 19:22:33 +00:00
_numPaths = np ;
pathIsConfirmed = true ;
2015-10-01 18:11:52 +00:00
_sortPaths ( now ) ;
2015-04-07 19:22:33 +00:00
}
2015-10-01 18:11:52 +00:00
2015-04-07 19:22:33 +00:00
} else {
2015-10-01 18:11:52 +00:00
2015-04-07 19:22:33 +00:00
/* 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 . */
2015-04-15 20:15:09 +00:00
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 ( ) ) ;
2015-09-24 23:21:36 +00:00
attemptToContactAt ( RR , localAddr , remoteAddr , now ) ;
2015-04-15 20:15:09 +00:00
}
2015-10-01 18:11:52 +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
}
2013-12-31 09:22:32 +00:00
2014-10-04 01:27:42 +00:00
/* Announce multicast groups of interest to direct peers if they are
* considered authorized members of a given network . Also announce to
2015-06-19 17:23:25 +00:00
* root servers and network controllers . */
2015-10-01 18:11:52 +00:00
/*
2015-04-07 19:22:33 +00:00
if ( ( pathIsConfirmed ) & & ( ( now - _lastAnnouncedTo ) > = ( ( ZT_MULTICAST_LIKE_EXPIRE / 2 ) - 1000 ) ) ) {
2014-10-13 21:12:51 +00:00
_lastAnnouncedTo = now ;
2014-09-30 15:38:03 +00:00
2015-06-19 17:23:25 +00:00
const bool isRoot = RR - > topology - > isRoot ( _id ) ;
2014-10-21 17:42:04 +00:00
2014-09-30 15:38:03 +00:00
Packet outp ( _id . address ( ) , RR - > identity . address ( ) , Packet : : VERB_MULTICAST_LIKE ) ;
2015-04-07 01:27:24 +00:00
const std : : vector < SharedPtr < Network > > networks ( RR - > node - > allNetworks ( ) ) ;
for ( std : : vector < SharedPtr < Network > > : : const_iterator n ( networks . begin ( ) ) ; n ! = networks . end ( ) ; + + n ) {
2015-07-31 16:37:13 +00:00
if ( ( isRoot ) | | ( ( * n ) - > isAllowed ( _id . address ( ) ) ) | | ( _id . address ( ) = = ( * n ) - > controller ( ) ) ) {
2015-04-07 01:27:24 +00:00
const std : : vector < MulticastGroup > mgs ( ( * n ) - > allMulticastGroups ( ) ) ;
for ( std : : vector < MulticastGroup > : : const_iterator mg ( mgs . begin ( ) ) ; mg ! = mgs . end ( ) ; + + mg ) {
2014-09-30 15:38:03 +00:00
if ( ( outp . size ( ) + 18 ) > ZT_UDP_DEFAULT_PAYLOAD_MTU ) {
outp . armor ( _key , true ) ;
2015-09-24 23:21:36 +00:00
RR - > node - > putPacket ( localAddr , remoteAddr , outp . data ( ) , outp . size ( ) ) ;
2014-09-30 15:38:03 +00:00
outp . reset ( _id . address ( ) , RR - > identity . address ( ) , Packet : : VERB_MULTICAST_LIKE ) ;
}
// network ID, MAC, ADI
outp . append ( ( uint64_t ) ( * n ) - > id ( ) ) ;
mg - > mac ( ) . appendTo ( outp ) ;
outp . append ( ( uint32_t ) mg - > adi ( ) ) ;
}
}
}
if ( outp . size ( ) > ZT_PROTO_MIN_PACKET_LENGTH ) {
outp . armor ( _key , true ) ;
2015-09-24 23:21:36 +00:00
RR - > node - > putPacket ( localAddr , remoteAddr , outp . data ( ) , outp . size ( ) ) ;
2014-09-30 15:38:03 +00:00
}
2014-01-30 22:23:52 +00:00
}
2015-10-01 18:11:52 +00:00
*/
2013-07-13 18:28:26 +00:00
}
2013-07-04 20:56:19 +00:00
2014-06-11 04:41:34 +00:00
if ( ( verb = = Packet : : VERB_FRAME ) | | ( verb = = Packet : : VERB_EXT_FRAME ) )
2013-07-13 18:28:26 +00:00
_lastUnicastFrame = now ;
2015-04-03 00:54:56 +00:00
else if ( verb = = Packet : : VERB_MULTICAST_FRAME )
2013-07-13 18:28:26 +00:00
_lastMulticastFrame = now ;
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 ) ;
switch ( atAddress . ss_family ) {
case AF_INET :
outp . append ( ( unsigned char ) ZT_PROTO_DEST_ADDRESS_TYPE_IPV4 ) ;
outp . append ( atAddress . rawIpData ( ) , 4 ) ;
outp . append ( ( uint16_t ) atAddress . port ( ) ) ;
break ;
case AF_INET6 :
outp . append ( ( unsigned char ) ZT_PROTO_DEST_ADDRESS_TYPE_IPV6 ) ;
outp . append ( atAddress . rawIpData ( ) , 16 ) ;
outp . append ( ( uint16_t ) atAddress . port ( ) ) ;
break ;
default :
outp . append ( ( unsigned char ) ZT_PROTO_DEST_ADDRESS_TYPE_NONE ) ;
break ;
}
outp . armor ( _key , false ) ; // HELLO is sent in the clear
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-04-08 02:31:11 +00:00
void Peer : : doPingAndKeepalive ( const RuntimeEnvironment * RR , uint64_t now )
{
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
RemotePath * const bestPath = _getBestPath ( now ) ;
2015-07-31 16:37:13 +00:00
if ( bestPath ) {
2015-04-08 02:31:11 +00:00
if ( ( now - bestPath - > lastReceived ( ) ) > = ZT_PEER_DIRECT_PING_DELAY ) {
2015-05-21 22:58:26 +00:00
TRACE ( " PING %s(%s) " , _id . address ( ) . toString ( ) . c_str ( ) , bestPath - > address ( ) . toString ( ) . c_str ( ) ) ;
2015-09-24 23:21:36 +00:00
attemptToContactAt ( RR , bestPath - > localAddress ( ) , bestPath - > address ( ) , now ) ;
2015-04-08 02:31:11 +00:00
bestPath - > sent ( now ) ;
2015-07-13 17:03:04 +00:00
} else if ( ( ( now - bestPath - > lastSend ( ) ) > = ZT_NAT_KEEPALIVE_DELAY ) & & ( ! bestPath - > reliable ( ) ) ) {
2015-09-23 17:27:53 +00:00
_natKeepaliveBuf + = ( uint32_t ) ( ( now * 0x9e3779b1 ) > > 1 ) ; // tumble this around to send constantly varying (meaningless) payloads
2015-05-21 22:58:26 +00:00
TRACE ( " NAT keepalive %s(%s) " , _id . address ( ) . toString ( ) . c_str ( ) , bestPath - > address ( ) . toString ( ) . c_str ( ) ) ;
2015-09-24 23:21:36 +00:00
RR - > node - > putPacket ( bestPath - > localAddress ( ) , bestPath - > address ( ) , & _natKeepaliveBuf , sizeof ( _natKeepaliveBuf ) ) ;
2015-05-21 22:58:26 +00:00
bestPath - > sent ( now ) ;
2015-04-08 02:31:11 +00:00
}
}
}
2015-07-07 17:00:34 +00:00
void Peer : : pushDirectPaths ( const RuntimeEnvironment * RR , RemotePath * path , uint64_t now , bool force )
2015-07-06 21:39:28 +00:00
{
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2015-07-28 18:43:09 +00:00
if ( ( ( now - _lastDirectPathPush ) > = ZT_DIRECT_PATH_PUSH_INTERVAL ) | | ( force ) ) {
2015-07-06 21:39:28 +00:00
_lastDirectPathPush = now ;
2015-07-07 17:00:34 +00:00
std : : vector < Path > dps ( RR - > node - > directPaths ( ) ) ;
2015-07-28 00:02:43 +00:00
2015-07-13 17:35:33 +00:00
# ifdef ZT_TRACE
{
std : : string ps ;
for ( std : : vector < Path > : : const_iterator p ( dps . begin ( ) ) ; p ! = dps . end ( ) ; + + p ) {
if ( ps . length ( ) > 0 )
ps . push_back ( ' , ' ) ;
ps . append ( p - > address ( ) . toString ( ) ) ;
}
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-07-06 21:39:28 +00:00
std : : vector < Path > : : const_iterator p ( dps . begin ( ) ) ;
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 ;
switch ( p - > address ( ) . ss_family ) {
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-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
}
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-07-06 21:39:28 +00:00
outp . append ( p - > address ( ) . rawIpData ( ) , ( ( addressType = = 4 ) ? 4 : 16 ) ) ;
outp . append ( ( uint16_t ) p - > address ( ) . port ( ) ) ;
+ + 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-10-01 18:11:52 +00:00
void Peer : : addPath ( const RemotePath & newp , uint64_t now )
2014-10-21 17:42:04 +00:00
{
2015-10-01 18:11:52 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-10-21 17:42:04 +00:00
unsigned int np = _numPaths ;
2015-04-03 00:54:56 +00:00
2014-10-21 17:42:04 +00:00
for ( unsigned int p = 0 ; p < np ; + + p ) {
2015-04-03 00:54:56 +00:00
if ( _paths [ p ] . address ( ) = = newp . address ( ) ) {
2014-10-21 17:42:04 +00:00
_paths [ p ] . setFixed ( newp . fixed ( ) ) ;
2015-10-01 18:11:52 +00:00
_sortPaths ( now ) ;
2014-10-21 17:42:04 +00:00
return ;
}
}
2015-04-03 00:54:56 +00:00
2015-07-06 21:08:13 +00:00
RemotePath * slot = ( RemotePath * ) 0 ;
2015-09-24 23:21:36 +00:00
if ( np < ZT_MAX_PEER_NETWORK_PATHS ) {
2015-04-03 00:54:56 +00:00
// Add new path
slot = & ( _paths [ np + + ] ) ;
} else {
// Replace oldest non-fixed path
uint64_t slotLRmin = 0xffffffffffffffffULL ;
2015-09-24 23:21:36 +00:00
for ( unsigned int p = 0 ; p < ZT_MAX_PEER_NETWORK_PATHS ; + + p ) {
2015-04-03 00:54:56 +00:00
if ( ( ! _paths [ p ] . fixed ( ) ) & & ( _paths [ p ] . lastReceived ( ) < = slotLRmin ) ) {
slotLRmin = _paths [ p ] . lastReceived ( ) ;
slot = & ( _paths [ p ] ) ;
}
}
}
if ( slot ) {
* slot = newp ;
_numPaths = np ;
2014-10-21 17:42:04 +00:00
}
2015-10-01 18:11:52 +00:00
_sortPaths ( now ) ;
2014-10-21 17:42:04 +00:00
}
void Peer : : clearPaths ( bool fixedToo )
{
if ( fixedToo ) {
_numPaths = 0 ;
} else {
unsigned int np = _numPaths ;
unsigned int x = 0 ;
unsigned int y = 0 ;
while ( x < np ) {
if ( _paths [ x ] . fixed ( ) )
_paths [ y + + ] = _paths [ x ] ;
+ + x ;
}
_numPaths = y ;
2014-04-04 00:12:34 +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 ) {
if ( _paths [ x ] . fixed ( ) ) {
2015-09-24 23:21:36 +00:00
attemptToContactAt ( RR , _paths [ x ] . localAddress ( ) , _paths [ x ] . address ( ) , now ) ;
2015-04-07 18:56:10 +00:00
_paths [ y + + ] = _paths [ x ] ; // keep fixed paths
}
} else {
_paths [ y + + ] = _paths [ x ] ; // keep paths not in this scope
}
+ + 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 ) ) {
TRACE ( " rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network " , ( unsigned long long ) _id , cert . signedBy ( ) . toString ( ) . c_str ( ) ) ;
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 ) ) {
TRACE ( " rejected network membership certificate for %.16llx self signed by %s: signature check failed " , ( unsigned long long ) _id , cert . signedBy ( ) . toString ( ) . c_str ( ) ) ;
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 ( ) ) ) {
TRACE ( " rejected network membership certificate for %.16llx signed by %s: signature check failed " , ( unsigned long long ) _id , cert . signedBy ( ) . toString ( ) . c_str ( ) ) ;
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 ;
return ( ( now - tmp ) < ( ZT_NETWORK_AUTOCONF_DELAY / 2 ) ) ;
}
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 ) ;
}
}
}
void Peer : : _sortPaths ( const uint64_t now )
{
// assumes _lock is locked
_lastPathSort = now ;
std : : sort ( & ( _paths [ 0 ] ) , & ( _paths [ _numPaths ] ) , _SortPathsByQuality ( now ) ) ;
}
RemotePath * Peer : : _getBestPath ( const uint64_t now )
{
// 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 ] ) ;
}
return ( RemotePath * ) 0 ;
}
2013-07-04 20:56:19 +00:00
} // namespace ZeroTier