@ -59,8 +59,6 @@
# include "../osdep/ManagedRoute.hpp"
# include "OneService.hpp"
# include "ClusterGeoIpService.hpp"
# include "ClusterDefinition.hpp"
# include "SoftwareUpdater.hpp"
# ifdef __WINDOWS__
@ -157,9 +155,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
// Maximum write buffer size for outgoing TCP connections (sanity limit)
# define ZT_TCP_MAX_WRITEQ_SIZE 33554432
// How often to check TCP connections and cluster links and send status to cluster peers
# define ZT_TCP_CHECK_PERIOD 15000
// TCP activity timeout
# define ZT_TCP_ACTIVITY_TIMEOUT 60000
@ -311,9 +306,9 @@ static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr
static void SnodeEventCallback ( ZT_Node * node , void * uptr , void * tptr , enum ZT_Event event , const void * metaData ) ;
static void SnodeStatePutFunction ( ZT_Node * node , void * uptr , void * tptr , enum ZT_StateObjectType type , const uint64_t id [ 2 ] , const void * data , int len ) ;
static int SnodeStateGetFunction ( ZT_Node * node , void * uptr , void * tptr , enum ZT_StateObjectType type , const uint64_t id [ 2 ] , void * data , unsigned int maxlen ) ;
static int SnodeWirePacketSendFunction ( ZT_Node * node , void * uptr , void * tptr , const struct sockaddr_storage * localAddr , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl ) ;
static int SnodeWirePacketSendFunction ( ZT_Node * node , void * uptr , void * tptr , int64_t localSocket , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl ) ;
static void SnodeVirtualNetworkFrameFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t nwid , void * * nuptr , uint64_t sourceMac , uint64_t destMac , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len ) ;
static int SnodePathCheckFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , const struct sockaddr_storage * localAddr , const struct sockaddr_storage * remoteAddr ) ;
static int SnodePathCheckFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , int64_t localSocket , const struct sockaddr_storage * remoteAddr ) ;
static int SnodePathLookupFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , int family , struct sockaddr_storage * result ) ;
static void StapFrameHandler ( void * uptr , void * tptr , uint64_t nwid , const MAC & from , const MAC & to , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len ) ;
@ -362,8 +357,7 @@ struct TcpConnection
TCP_UNCATEGORIZED_INCOMING , // uncategorized incoming connection
TCP_HTTP_INCOMING ,
TCP_HTTP_OUTGOING ,
TCP_TUNNEL_OUTGOING , // TUNNELED mode proxy outbound connection
TCP_CLUSTER_BACKPLANE
TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection
} type ;
OneServiceImpl * parent ;
@ -380,29 +374,11 @@ struct TcpConnection
std : : string status ;
std : : map < std : : string , std : : string > headers ;
// Used for cluster backplane connections
uint64_t clusterMemberId ;
unsigned int clusterMemberVersionMajor ;
unsigned int clusterMemberVersionMinor ;
unsigned int clusterMemberVersionRev ;
std : : vector < InetAddress > clusterMemberLocalAddresses ;
Mutex clusterMemberLocalAddresses_m ;
std : : string readq ;
std : : string writeq ;
Mutex writeq_m ;
} ;
/**
* Message types for cluster backplane communication
*/
enum ClusterMessageType
{
CLUSTER_MESSAGE_STATUS = 0 ,
CLUSTER_MESSAGE_STATE_OBJECT = 1 ,
CLUSTER_MESSAGE_PROXY_SEND = 2
} ;
class OneServiceImpl : public OneService
{
public :
@ -421,8 +397,6 @@ public:
bool _updateAutoApply ;
unsigned int _primaryPort ;
volatile unsigned int _udpPortPickerCounter ;
uint64_t _clusterMemberId ;
uint8_t _clusterKey [ 32 ] ; // secret key for cluster backplane config
// Local configuration and memo-ized information from it
json _localConfig ;
@ -434,7 +408,6 @@ public:
std : : vector < InetAddress > _globalV6Blacklist ;
std : : vector < InetAddress > _allowManagementFrom ;
std : : vector < std : : string > _interfacePrefixBlacklist ;
std : : vector < InetAddress > _clusterBackplaneAddresses ;
Mutex _localConfig_m ;
/*
@ -518,7 +491,6 @@ public:
, _updateAutoApply ( false )
, _primaryPort ( port )
, _udpPortPickerCounter ( 0 )
, _clusterMemberId ( 0 )
, _lastDirectReceiveFromGlobal ( 0 )
# ifdef ZT_TCP_FALLBACK_RELAY
, _lastSendToGlobalV4 ( 0 )
@ -754,23 +726,6 @@ public:
}
}
// Derive the cluster's shared secret backplane encryption key by hashing its shared secret identity
{
uint8_t tmp [ 64 ] ;
uint8_t sk [ ZT_C25519_PRIVATE_KEY_LEN + 4 ] ;
memcpy ( sk , _node - > identity ( ) . privateKeyPair ( ) . priv . data , ZT_C25519_PRIVATE_KEY_LEN ) ;
sk [ ZT_C25519_PRIVATE_KEY_LEN ] = 0xab ;
sk [ ZT_C25519_PRIVATE_KEY_LEN + 1 ] = 0xcd ;
sk [ ZT_C25519_PRIVATE_KEY_LEN + 2 ] = 0xef ;
sk [ ZT_C25519_PRIVATE_KEY_LEN + 3 ] = 0xab ; // add an arbitrary nonce, just because
SHA512 : : hash ( tmp , sk , ZT_C25519_PRIVATE_KEY_LEN + 4 ) ;
memcpy ( _clusterKey , tmp , 32 ) ;
}
// Assign a random non-zero cluster member ID to identify vs. other cluster members
Utils : : getSecureRandom ( & _clusterMemberId , sizeof ( _clusterMemberId ) ) ;
if ( ! _clusterMemberId ) _clusterMemberId = 1 ;
// Main I/O loop
_nextBackgroundTaskDeadline = 0 ;
uint64_t clockShouldBe = OSUtils : : now ( ) ;
@ -779,7 +734,6 @@ public:
uint64_t lastBindRefresh = 0 ;
uint64_t lastUpdateCheck = clockShouldBe ;
uint64_t lastLocalInterfaceAddressCheck = ( clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL ) + 15000 ; // do this in 15s to give portmapper time to configure and other things time to settle
uint64_t lastTcpCheck = 0 ;
for ( ; ; ) {
_run_m . lock ( ) ;
if ( ! _run ) {
@ -873,58 +827,6 @@ public:
_node - > addLocalInterfaceAddress ( reinterpret_cast < const struct sockaddr_storage * > ( & ( * i ) ) ) ;
}
// Check TCP connections and cluster links
if ( ( now - lastTcpCheck ) > = ZT_TCP_CHECK_PERIOD ) {
lastTcpCheck = now ;
// Send status to active cluster links and close overflowed and dead ones
std : : vector < PhySocket * > toClose ;
std : : vector < InetAddress > clusterLinksUp ;
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
for ( std : : vector < TcpConnection * > : : const_iterator c ( _tcpConnections . begin ( ) ) ; c ! = _tcpConnections . end ( ) ; + + c ) {
TcpConnection * const tc = * c ;
tc - > writeq_m . lock ( ) ;
const unsigned long wql = ( unsigned long ) tc - > writeq . length ( ) ;
tc - > writeq_m . unlock ( ) ;
if ( ( tc - > sock ) & & ( ( wql > ZT_TCP_MAX_WRITEQ_SIZE ) | | ( ( now - tc - > lastReceive ) > ZT_TCP_ACTIVITY_TIMEOUT ) ) ) {
toClose . push_back ( tc - > sock ) ;
} else if ( ( tc - > type = = TcpConnection : : TCP_CLUSTER_BACKPLANE ) & & ( tc - > clusterMemberId ) ) {
clusterLinksUp . push_back ( tc - > remoteAddr ) ;
sendMyCurrentClusterState ( tc ) ;
}
}
}
for ( std : : vector < PhySocket * > : : iterator s ( toClose . begin ( ) ) ; s ! = toClose . end ( ) ; + + s )
_phy . close ( * s , true ) ;
// Attempt to connect to cluster links we don't have an active connection to
{
Mutex : : Lock _l ( _localConfig_m ) ;
for ( std : : vector < InetAddress > : : const_iterator ca ( _clusterBackplaneAddresses . begin ( ) ) ; ca ! = _clusterBackplaneAddresses . end ( ) ; + + ca ) {
if ( ( std : : find ( clusterLinksUp . begin ( ) , clusterLinksUp . end ( ) , * ca ) = = clusterLinksUp . end ( ) ) & & ( ! _binder . isBoundLocalInterfaceAddress ( * ca ) ) ) {
TcpConnection * tc = new TcpConnection ( ) ;
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
_tcpConnections . push_back ( tc ) ;
}
tc - > type = TcpConnection : : TCP_CLUSTER_BACKPLANE ;
tc - > remoteAddr = * ca ;
tc - > lastReceive = OSUtils : : now ( ) ;
tc - > parent = this ;
tc - > sock = ( PhySocket * ) 0 ; // set in connect handler
tc - > messageSize = 0 ;
tc - > clusterMemberId = 0 ; // not known yet
bool connected = false ;
_phy . tcpConnect ( reinterpret_cast < const struct sockaddr * > ( & ( * ca ) ) , connected , ( void * ) tc , true ) ;
}
}
}
}
const unsigned long delay = ( dl > now ) ? ( unsigned long ) ( dl - now ) : 100 ;
clockShouldBe = now + ( uint64_t ) delay ;
_phy . poll ( delay ) ;
@ -1211,21 +1113,6 @@ public:
res [ " planetWorldId " ] = planet . id ( ) ;
res [ " planetWorldTimestamp " ] = planet . timestamp ( ) ;
{
json cj ( json : : object ( ) ) ;
Mutex : : Lock _l ( _tcpConnections_m ) ;
Mutex : : Lock _l2 ( _localConfig_m ) ;
for ( std : : vector < InetAddress > : : const_iterator ca ( _clusterBackplaneAddresses . begin ( ) ) ; ca ! = _clusterBackplaneAddresses . end ( ) ; + + ca ) {
uint64_t up = 0 ;
for ( std : : vector < TcpConnection * > : : const_iterator c ( _tcpConnections . begin ( ) ) ; c ! = _tcpConnections . end ( ) ; + + c ) {
if ( ( ( * c ) - > remoteAddr = = * ca ) & & ( ( * c ) - > clusterMemberId ) & & ( ( * c ) - > lastReceive > up ) )
up = ( * c ) - > lastReceive ;
}
cj [ ca - > toString ( ) ] = up ;
}
res [ " cluster " ] = cj ;
}
scode = 200 ;
} else if ( ps [ 0 ] = = " moon " ) {
std : : vector < World > moons ( _node - > moons ( ) ) ;
@ -1576,16 +1463,6 @@ public:
}
}
json & cl = settings [ " cluster " ] ;
_clusterBackplaneAddresses . clear ( ) ;
if ( cl . is_array ( ) ) {
for ( unsigned long i = 0 ; i < cl . size ( ) ; + + i ) {
const InetAddress cip ( OSUtils : : jsonString ( cl [ i ] , " " ) ) ;
if ( ( cip . ss_family = = AF_INET ) | | ( cip . ss_family = = AF_INET6 ) )
_clusterBackplaneAddresses . push_back ( cip ) ;
}
}
json & controllerDbHttpHost = settings [ " controllerDbHttpHost " ] ;
json & controllerDbHttpPort = settings [ " controllerDbHttpPort " ] ;
json & controllerDbHttpPath = settings [ " controllerDbHttpPath " ] ;
@ -1754,250 +1631,6 @@ public:
}
}
// =========================================================================
// Cluster messaging functions
// =========================================================================
// mlen must be at least 24
void encryptClusterMessage ( char * data , unsigned int mlen )
{
uint8_t key [ 32 ] ;
memcpy ( key , _clusterKey , 32 ) ;
for ( int i = 0 ; i < 8 ; + + i ) key [ i ] ^ = data [ i ] ;
Salsa20 s20 ( key , data + 8 ) ;
uint8_t macKey [ 32 ] ;
uint8_t mac [ 16 ] ;
memset ( macKey , 0 , 32 ) ;
s20 . crypt12 ( macKey , macKey , 32 ) ;
s20 . crypt12 ( data + 24 , data + 24 , mlen - 24 ) ;
Poly1305 : : compute ( mac , data + 24 , mlen - 24 , macKey ) ;
memcpy ( data + 16 , mac , 8 ) ;
}
void announceStatusToClusterMember ( TcpConnection * tc )
{
try {
Buffer < 8194 > buf ;
buf . appendRandom ( 16 ) ;
buf . addSize ( 8 ) ; // space for MAC
buf . append ( ( uint8_t ) CLUSTER_MESSAGE_STATUS ) ;
buf . append ( _clusterMemberId ) ;
buf . append ( ( uint16_t ) ZEROTIER_ONE_VERSION_MAJOR ) ;
buf . append ( ( uint16_t ) ZEROTIER_ONE_VERSION_MINOR ) ;
buf . append ( ( uint16_t ) ZEROTIER_ONE_VERSION_REVISION ) ;
std : : vector < InetAddress > lif ( _binder . allBoundLocalInterfaceAddresses ( ) ) ;
buf . append ( ( uint16_t ) lif . size ( ) ) ;
for ( std : : vector < InetAddress > : : const_iterator i ( lif . begin ( ) ) ; i ! = lif . end ( ) ; + + i )
i - > serialize ( buf ) ;
Mutex : : Lock _l ( tc - > writeq_m ) ;
if ( tc - > writeq . length ( ) = = 0 )
_phy . setNotifyWritable ( tc - > sock , true ) ;
const unsigned int mlen = buf . size ( ) ;
tc - > writeq . push_back ( ( char ) ( ( mlen > > 16 ) & 0xff ) ) ;
tc - > writeq . push_back ( ( char ) ( ( mlen > > 8 ) & 0xff ) ) ;
tc - > writeq . push_back ( ( char ) ( mlen & 0xff ) ) ;
char * const data = reinterpret_cast < char * > ( buf . unsafeData ( ) ) ;
encryptClusterMessage ( data , mlen ) ;
tc - > writeq . append ( data , mlen ) ;
} catch ( . . . ) {
fprintf ( stderr , " WARNING: unexpected exception announcing status to cluster members " ZT_EOL_S ) ;
}
}
bool proxySendViaCluster ( const InetAddress & fromAddress , const InetAddress & dest , const void * data , unsigned int len , unsigned int ttl )
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
for ( std : : vector < TcpConnection * > : : const_iterator c ( _tcpConnections . begin ( ) ) ; c ! = _tcpConnections . end ( ) ; + + c ) {
TcpConnection * const tc = * c ;
if ( ( tc - > type = = TcpConnection : : TCP_CLUSTER_BACKPLANE ) & & ( tc - > clusterMemberId ) ) {
Mutex : : Lock _l2 ( tc - > clusterMemberLocalAddresses_m ) ;
for ( std : : vector < InetAddress > : : const_iterator i ( tc - > clusterMemberLocalAddresses . begin ( ) ) ; i ! = tc - > clusterMemberLocalAddresses . end ( ) ; + + i ) {
if ( * i = = fromAddress ) {
Buffer < 1024 > buf ;
buf . appendRandom ( 16 ) ;
buf . addSize ( 8 ) ; // space for MAC
buf . append ( ( uint8_t ) CLUSTER_MESSAGE_PROXY_SEND ) ;
buf . append ( ( uint8_t ) ttl ) ;
dest . serialize ( buf ) ;
fromAddress . serialize ( buf ) ;
Mutex : : Lock _l3 ( tc - > writeq_m ) ;
if ( tc - > writeq . length ( ) = = 0 )
_phy . setNotifyWritable ( tc - > sock , true ) ;
const unsigned int mlen = buf . size ( ) + len ;
tc - > writeq . push_back ( ( char ) ( ( mlen > > 16 ) & 0xff ) ) ;
tc - > writeq . push_back ( ( char ) ( ( mlen > > 8 ) & 0xff ) ) ;
tc - > writeq . push_back ( ( char ) ( mlen & 0xff ) ) ;
const unsigned long startpos = ( unsigned long ) tc - > writeq . length ( ) ;
tc - > writeq . append ( reinterpret_cast < const char * > ( buf . data ( ) ) , buf . size ( ) ) ;
tc - > writeq . append ( reinterpret_cast < const char * > ( data ) , len ) ;
char * const outdata = const_cast < char * > ( tc - > writeq . data ( ) ) + startpos ;
encryptClusterMessage ( outdata , mlen ) ;
return true ;
}
}
}
}
return false ;
}
void replicateStateObject ( const ZT_StateObjectType type , const uint64_t id [ 2 ] , const void * const data , const unsigned int len , TcpConnection * tc )
{
char buf [ 42 ] ;
Mutex : : Lock _l2 ( tc - > writeq_m ) ;
if ( tc - > writeq . length ( ) = = 0 )
_phy . setNotifyWritable ( tc - > sock , true ) ;
const unsigned int mlen = len + 42 ;
tc - > writeq . push_back ( ( char ) ( ( mlen > > 16 ) & 0xff ) ) ;
tc - > writeq . push_back ( ( char ) ( ( mlen > > 8 ) & 0xff ) ) ;
tc - > writeq . push_back ( ( char ) ( mlen & 0xff ) ) ;
Utils : : getSecureRandom ( buf , 16 ) ;
buf [ 24 ] = ( char ) CLUSTER_MESSAGE_STATE_OBJECT ;
buf [ 25 ] = ( char ) type ;
buf [ 26 ] = ( char ) ( ( id [ 0 ] > > 56 ) & 0xff ) ;
buf [ 27 ] = ( char ) ( ( id [ 0 ] > > 48 ) & 0xff ) ;
buf [ 28 ] = ( char ) ( ( id [ 0 ] > > 40 ) & 0xff ) ;
buf [ 29 ] = ( char ) ( ( id [ 0 ] > > 32 ) & 0xff ) ;
buf [ 30 ] = ( char ) ( ( id [ 0 ] > > 24 ) & 0xff ) ;
buf [ 31 ] = ( char ) ( ( id [ 0 ] > > 16 ) & 0xff ) ;
buf [ 32 ] = ( char ) ( ( id [ 0 ] > > 8 ) & 0xff ) ;
buf [ 33 ] = ( char ) ( id [ 0 ] & 0xff ) ;
buf [ 34 ] = ( char ) ( ( id [ 1 ] > > 56 ) & 0xff ) ;
buf [ 35 ] = ( char ) ( ( id [ 1 ] > > 48 ) & 0xff ) ;
buf [ 36 ] = ( char ) ( ( id [ 1 ] > > 40 ) & 0xff ) ;
buf [ 37 ] = ( char ) ( ( id [ 1 ] > > 32 ) & 0xff ) ;
buf [ 38 ] = ( char ) ( ( id [ 1 ] > > 24 ) & 0xff ) ;
buf [ 39 ] = ( char ) ( ( id [ 1 ] > > 16 ) & 0xff ) ;
buf [ 40 ] = ( char ) ( ( id [ 1 ] > > 8 ) & 0xff ) ;
buf [ 41 ] = ( char ) ( id [ 1 ] & 0xff ) ;
const unsigned long startpos = ( unsigned long ) tc - > writeq . length ( ) ;
tc - > writeq . append ( buf , 42 ) ;
tc - > writeq . append ( reinterpret_cast < const char * > ( data ) , len ) ;
char * const outdata = const_cast < char * > ( tc - > writeq . data ( ) ) + startpos ;
encryptClusterMessage ( outdata , mlen ) ;
tc - > writeq . append ( outdata , mlen ) ;
}
void writeStateObject ( enum ZT_StateObjectType type , const uint64_t id [ 2 ] , const void * data , int len )
{
char buf [ 65535 ] ;
char p [ 1024 ] ;
FILE * f ;
bool secure = false ;
switch ( type ) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.public " , _homePath . c_str ( ) ) ;
break ;
case ZT_STATE_OBJECT_IDENTITY_SECRET :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.secret " , _homePath . c_str ( ) ) ;
secure = true ;
break ;
//case ZT_STATE_OBJECT_PEER_STATE:
// break;
case ZT_STATE_OBJECT_NETWORK_CONFIG :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " networks.d/%.16llx.conf " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
secure = true ;
break ;
//case ZT_STATE_OBJECT_NETWORK_MEMBERSHIP:
// break;
case ZT_STATE_OBJECT_PLANET :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " planet " , _homePath . c_str ( ) ) ;
break ;
case ZT_STATE_OBJECT_MOON :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " moons.d/%.16llx.moon " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
break ;
default :
p [ 0 ] = ( char ) 0 ;
break ;
}
if ( p [ 0 ] ) {
if ( len > = 0 ) {
// Check to see if we've already written this first. This reduces
// redundant writes and I/O overhead on most platforms and has
// little effect on others.
f = fopen ( p , " r " ) ;
bool redundant = false ;
if ( f ) {
long l = ( long ) fread ( buf , 1 , sizeof ( buf ) , f ) ;
fclose ( f ) ;
redundant = ( ( l = = ( long ) len ) & & ( memcmp ( data , buf , l ) = = 0 ) ) ;
}
if ( ! redundant ) {
f = fopen ( p , " w " ) ;
if ( f ) {
if ( fwrite ( data , len , 1 , f ) ! = 1 )
fprintf ( stderr , " WARNING: unable to write to file: %s (I/O error) " ZT_EOL_S , p ) ;
fclose ( f ) ;
if ( secure )
OSUtils : : lockDownFile ( p , false ) ;
} else {
fprintf ( stderr , " WARNING: unable to write to file: %s (unable to open) " ZT_EOL_S , p ) ;
}
}
} else {
OSUtils : : rm ( p ) ;
}
}
}
void sendMyCurrentClusterState ( TcpConnection * tc )
{
// We currently don't need to dump everything. Networks and moons are most important.
// The rest will get caught up rapidly due to constant peer updates, etc.
std : : string buf ;
std : : vector < std : : string > l ( OSUtils : : listDirectory ( ( _homePath + ZT_PATH_SEPARATOR_S + " networks.d " ) . c_str ( ) , false ) ) ;
for ( std : : vector < std : : string > : : const_iterator f ( l . begin ( ) ) ; f ! = l . end ( ) ; + + f ) {
buf . clear ( ) ;
if ( OSUtils : : readFile ( ( _homePath + ZT_PATH_SEPARATOR_S + * f ) . c_str ( ) , buf ) ) {
if ( f - > length ( ) = = 21 ) {
const uint64_t nwid = Utils : : hexStrToU64 ( f - > substr ( 0 , 16 ) . c_str ( ) ) ;
if ( nwid ) {
uint64_t tmp [ 2 ] ;
tmp [ 0 ] = nwid ;
tmp [ 1 ] = 0 ;
replicateStateObject ( ZT_STATE_OBJECT_NETWORK_CONFIG , tmp , buf . data ( ) , ( int ) buf . length ( ) , tc ) ;
}
}
}
}
l = OSUtils : : listDirectory ( ( _homePath + ZT_PATH_SEPARATOR_S + " moons.d " ) . c_str ( ) , false ) ;
for ( std : : vector < std : : string > : : const_iterator f ( l . begin ( ) ) ; f ! = l . end ( ) ; + + f ) {
buf . clear ( ) ;
if ( OSUtils : : readFile ( ( _homePath + ZT_PATH_SEPARATOR_S + * f ) . c_str ( ) , buf ) ) {
if ( f - > length ( ) = = 21 ) {
const uint64_t moonId = Utils : : hexStrToU64 ( f - > substr ( 0 , 16 ) . c_str ( ) ) ;
if ( moonId ) {
uint64_t tmp [ 2 ] ;
tmp [ 0 ] = moonId ;
tmp [ 1 ] = 0 ;
replicateStateObject ( ZT_STATE_OBJECT_MOON , tmp , buf . data ( ) , ( int ) buf . length ( ) , tc ) ;
}
}
}
}
}
// =========================================================================
// Handlers for Node and Phy<> callbacks
// =========================================================================
@ -2010,7 +1643,7 @@ public:
const ZT_ResultCode rc = _node - > processWirePacket (
( void * ) 0 ,
OSUtils : : now ( ) ,
reinterpret_cast < const struct sockaddr_storage * > ( localAddr ) ,
( int64_t ) ( ( uintptr_t ) sock ) ,
( const struct sockaddr_storage * ) from , // Phy<> uses sockaddr_storage, so it'll always be that big
data ,
len ,
@ -2044,13 +1677,6 @@ public:
_phy . close ( _tcpFallbackTunnel - > sock ) ;
_tcpFallbackTunnel = tc ;
_phy . streamSend ( sock , ZT_TCP_TUNNEL_HELLO , sizeof ( ZT_TCP_TUNNEL_HELLO ) ) ;
} else if ( tc - > type = = TcpConnection : : TCP_CLUSTER_BACKPLANE ) {
{
Mutex : : Lock _l ( tc - > writeq_m ) ;
tc - > writeq . push_back ( ( char ) 0x93 ) ; // identifies type of connection as cluster backplane
}
announceStatusToClusterMember ( tc ) ;
_phy . setNotifyWritable ( sock , true ) ;
} else {
_phy . close ( sock , true ) ;
}
@ -2106,31 +1732,6 @@ public:
case TcpConnection : : TCP_UNCATEGORIZED_INCOMING :
switch ( reinterpret_cast < uint8_t * > ( data ) [ 0 ] ) {
// 0x93 is first byte of cluster backplane connections
case 0x93 : {
// We only allow this from cluster backplane IPs. We also authenticate
// each packet cryptographically, so this is just a first line of defense.
bool allow = false ;
{
Mutex : : Lock _l ( _localConfig_m ) ;
for ( std : : vector < InetAddress > : : const_iterator i ( _clusterBackplaneAddresses . begin ( ) ) ; i ! = _clusterBackplaneAddresses . end ( ) ; + + i ) {
if ( tc - > remoteAddr . ipsEqual ( * i ) ) {
allow = true ;
break ;
}
}
}
if ( allow ) {
tc - > type = TcpConnection : : TCP_CLUSTER_BACKPLANE ;
tc - > clusterMemberId = 0 ; // unknown, waiting for first status message
announceStatusToClusterMember ( tc ) ;
if ( len > 1 )
phyOnTcpData ( sock , uptr , reinterpret_cast < uint8_t * > ( data ) + 1 , len - 1 ) ;
} else {
_phy . close ( sock ) ;
}
} break ;
// HTTP: GET, PUT, POST, HEAD
case ' G ' :
case ' P ' :
@ -2223,7 +1824,7 @@ public:
const ZT_ResultCode rc = _node - > processWirePacket (
( void * ) 0 ,
OSUtils : : now ( ) ,
reinterpret_cast < struct sockaddr_storage * > ( & fakeTcpLocalInterfaceAddress ) ,
- 1 ,
reinterpret_cast < struct sockaddr_storage * > ( & from ) ,
data ,
plen ,
@ -2248,114 +1849,6 @@ public:
}
return ;
case TcpConnection : : TCP_CLUSTER_BACKPLANE :
tc - > readq . append ( ( const char * ) data , len ) ;
if ( tc - > readq . length ( ) > = 28 ) { // got 3-byte message size + 16-byte IV + 8-byte MAC + 1-byte type (encrypted)
uint8_t * data = reinterpret_cast < uint8_t * > ( const_cast < char * > ( tc - > readq . data ( ) ) ) ;
unsigned long mlen = ( ( ( unsigned long ) data [ 0 ] < < 16 ) | ( ( unsigned long ) data [ 1 ] < < 8 ) | ( unsigned long ) data [ 2 ] ) ;
if ( ( mlen < 25 ) | | ( mlen > ZT_TCP_MAX_WRITEQ_SIZE ) ) {
_phy . close ( sock ) ;
return ;
} else if ( tc - > readq . length ( ) > = ( mlen + 3 ) ) { // got entire message
data + = 3 ;
uint8_t key [ 32 ] ;
memcpy ( key , _clusterKey , 32 ) ;
for ( int i = 0 ; i < 8 ; + + i ) key [ i ] ^ = data [ i ] ; // first 8 bytes of IV get XORed with key
Salsa20 s20 ( key , data + 8 ) ; // last 8 bytes of IV are fed into Salsa20 directly as its 64-bit IV
uint8_t macKey [ 32 ] ;
uint8_t mac [ 16 ] ;
memset ( macKey , 0 , 32 ) ;
s20 . crypt12 ( macKey , macKey , 32 ) ;
Poly1305 : : compute ( mac , data + 24 , mlen - 24 , macKey ) ;
if ( ! Utils : : secureEq ( mac , data + 16 , 8 ) ) {
_phy . close ( sock ) ;
return ;
}
s20 . crypt12 ( data + 24 , data + 24 , mlen - 24 ) ;
switch ( ( ClusterMessageType ) data [ 24 ] ) {
case CLUSTER_MESSAGE_STATUS :
if ( mlen > ( 25 + 16 ) ) {
Buffer < 4096 > tmp ( data + 25 , mlen - 25 ) ;
try {
const uint64_t cmid = tmp . at < uint64_t > ( 0 ) ;
if ( cmid = = _clusterMemberId ) { // shouldn't happen, but don't allow self-to-self
_phy . close ( sock ) ;
return ;
}
if ( ! tc - > clusterMemberId ) {
tc - > clusterMemberId = cmid ;
sendMyCurrentClusterState ( tc ) ;
}
tc - > clusterMemberVersionMajor = tmp . at < uint16_t > ( 8 ) ;
tc - > clusterMemberVersionMinor = tmp . at < uint16_t > ( 10 ) ;
tc - > clusterMemberVersionRev = tmp . at < uint16_t > ( 12 ) ;
const unsigned int clusterMemberLocalAddressCount = tmp . at < uint16_t > ( 14 ) ;
std : : vector < InetAddress > la ;
unsigned int ptr = 16 ;
for ( unsigned int k = 0 ; k < clusterMemberLocalAddressCount ; + + k ) {
la . push_back ( InetAddress ( ) ) ;
ptr + = la . back ( ) . deserialize ( tmp , ptr ) ;
}
{
Mutex : : Lock _l2 ( tc - > clusterMemberLocalAddresses_m ) ;
tc - > clusterMemberLocalAddresses . swap ( la ) ;
}
} catch ( . . . ) { }
}
break ;
case CLUSTER_MESSAGE_STATE_OBJECT :
if ( mlen > 42 ) { // type + object ID + [data]
uint64_t objId [ 2 ] ;
objId [ 0 ] = (
( ( uint64_t ) data [ 26 ] < < 56 ) |
( ( uint64_t ) data [ 27 ] < < 48 ) |
( ( uint64_t ) data [ 28 ] < < 40 ) |
( ( uint64_t ) data [ 29 ] < < 32 ) |
( ( uint64_t ) data [ 30 ] < < 24 ) |
( ( uint64_t ) data [ 31 ] < < 16 ) |
( ( uint64_t ) data [ 32 ] < < 8 ) |
( uint64_t ) data [ 33 ]
) ;
objId [ 1 ] = (
( ( uint64_t ) data [ 34 ] < < 56 ) |
( ( uint64_t ) data [ 35 ] < < 48 ) |
( ( uint64_t ) data [ 36 ] < < 40 ) |
( ( uint64_t ) data [ 37 ] < < 32 ) |
( ( uint64_t ) data [ 38 ] < < 24 ) |
( ( uint64_t ) data [ 39 ] < < 16 ) |
( ( uint64_t ) data [ 40 ] < < 8 ) |
( uint64_t ) data [ 41 ]
) ;
if ( _node - > processStateUpdate ( ( void * ) 0 , ( ZT_StateObjectType ) data [ 25 ] , objId , data + 42 , ( unsigned int ) ( mlen - 42 ) ) = = ZT_RESULT_OK )
writeStateObject ( ( ZT_StateObjectType ) data [ 25 ] , objId , data + 42 , ( unsigned int ) ( mlen - 42 ) ) ;
}
break ;
case CLUSTER_MESSAGE_PROXY_SEND :
if ( mlen > 25 ) {
Buffer < 4096 > tmp ( data + 25 , mlen - 25 ) ;
try {
InetAddress dest , src ;
const unsigned int ttl = ( unsigned int ) tmp [ 0 ] ;
unsigned int ptr = 1 ;
ptr + = dest . deserialize ( tmp ) ;
ptr + = src . deserialize ( tmp , ptr ) ;
if ( ptr < tmp . size ( ) )
_binder . udpSend ( _phy , src , dest , reinterpret_cast < const uint8_t * > ( tmp . data ( ) ) + ptr , tmp . size ( ) - ptr , ttl ) ;
} catch ( . . . ) { }
}
break ;
}
tc - > readq . erase ( tc - > readq . begin ( ) , tc - > readq . begin ( ) + mlen ) ;
}
}
return ;
}
} catch ( . . . ) {
_phy . close ( sock ) ;
@ -2549,18 +2042,57 @@ public:
inline void nodeStatePutFunction ( enum ZT_StateObjectType type , const uint64_t id [ 2 ] , const void * data , int len )
{
writeStateObject ( type , id , data , len ) ;
char p [ 1024 ] ;
FILE * f ;
bool secure = false ;
std : : vector < uint64_t > sentTo ;
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
for ( std : : vector < TcpConnection * > : : const_iterator ci ( _tcpConnections . begin ( ) ) ; ci ! = _tcpConnections . end ( ) ; + + ci ) {
TcpConnection * const c = * ci ;
if ( ( c - > type = = TcpConnection : : TCP_CLUSTER_BACKPLANE ) & & ( c - > clusterMemberId ! = 0 ) & & ( std : : find ( sentTo . begin ( ) , sentTo . end ( ) , c - > clusterMemberId ) = = sentTo . end ( ) ) ) {
sentTo . push_back ( c - > clusterMemberId ) ;
replicateStateObject ( type , id , data , len , c ) ;
}
switch ( type ) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.public " , _homePath . c_str ( ) ) ;
break ;
case ZT_STATE_OBJECT_IDENTITY_SECRET :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.secret " , _homePath . c_str ( ) ) ;
secure = true ;
break ;
case ZT_STATE_OBJECT_PLANET :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " planet " , _homePath . c_str ( ) ) ;
break ;
case ZT_STATE_OBJECT_MOON :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " moons.d/%.16llx.moon " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
break ;
case ZT_STATE_OBJECT_NETWORK_CONFIG :
Utils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " networks.d/%.16llx.conf " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
secure = true ;
break ;
default :
return ;
}
if ( len > = 0 ) {
// Check to see if we've already written this first. This reduces
// redundant writes and I/O overhead on most platforms and has
// little effect on others.
f = fopen ( p , " r " ) ;
if ( f ) {
char buf [ 65535 ] ;
long l = ( long ) fread ( buf , 1 , sizeof ( buf ) , f ) ;
fclose ( f ) ;
if ( ( l = = ( long ) len ) & & ( memcmp ( data , buf , l ) = = 0 ) )
return ;
}
f = fopen ( p , " w " ) ;
if ( f ) {
if ( fwrite ( data , len , 1 , f ) ! = 1 )
fprintf ( stderr , " WARNING: unable to write to file: %s (I/O error) " ZT_EOL_S , p ) ;
fclose ( f ) ;
if ( secure )
OSUtils : : lockDownFile ( p , false ) ;
} else {
fprintf ( stderr , " WARNING: unable to write to file: %s (unable to open) " ZT_EOL_S , p ) ;
}
} else {
OSUtils : : rm ( p ) ;
}
}
@ -2596,7 +2128,7 @@ public:
return - 1 ;
}
inline int nodeWirePacketSendFunction ( const struct sockaddr_storage * localAddr , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl )
inline int nodeWirePacketSendFunction ( const int64_t localSocket , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl )
{
# ifdef ZT_TCP_FALLBACK_RELAY
if ( addr - > ss_family = = AF_INET ) {
@ -2646,20 +2178,13 @@ public:
// proxy fallback, which is slow.
# endif // ZT_TCP_FALLBACK_RELAY
switch ( _binder . udpSend ( _phy , * ( reinterpret_cast < const InetAddress * > ( localAddr ) ) , * ( reinterpret_cast < const InetAddress * > ( addr ) ) , data , len , ttl ) ) {
case - 1 : // local bound address not found, so see if a cluster peer owns it
if ( localAddr - > ss_family ! = 0 ) {
return ( proxySendViaCluster ( * ( reinterpret_cast < const InetAddress * > ( localAddr ) ) , * ( reinterpret_cast < const InetAddress * > ( addr ) ) , data , len , ttl ) ) ? 0 : - 1 ;
} else {
return - 1 ; // failure
}
break ;
case 0 : // failure
return - 1 ;
default : // success
return 0 ;
if ( ( localSocket ! = 0 ) & & ( localSocket ! = - 1 ) ) {
if ( ( ttl ) & & ( addr - > ss_family = = AF_INET ) ) _phy . setIp4UdpTtl ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) , ttl ) ;
const bool r = _phy . udpSend ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) , ( const struct sockaddr * ) addr , data , len ) ;
if ( ( ttl ) & & ( addr - > ss_family = = AF_INET ) ) _phy . setIp4UdpTtl ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) , 255 ) ;
return ( ( r ) ? 0 : - 1 ) ;
} else {
return ( ( _binder . udpSendAll ( _phy , addr , data , len , ttl ) ) ? 0 : - 1 ) ;
}
}
@ -2671,7 +2196,7 @@ public:
n - > tap - > put ( MAC ( sourceMac ) , MAC ( destMac ) , etherType , data , len ) ;
}
inline int nodePathCheckFunction ( uint64_t ztaddr , const struct sockaddr_storage * localAddr , const struct sockaddr_storage * remoteAddr )
inline int nodePathCheckFunction ( uint64_t ztaddr , const int64_t localSocket , const struct sockaddr_storage * remoteAddr )
{
// Make sure we're not trying to do ZeroTier-over-ZeroTier
{
@ -2882,12 +2407,12 @@ static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_St
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeStatePutFunction ( type , id , data , len ) ; }
static int SnodeStateGetFunction ( ZT_Node * node , void * uptr , void * tptr , enum ZT_StateObjectType type , const uint64_t id [ 2 ] , void * data , unsigned int maxlen )
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeStateGetFunction ( type , id , data , maxlen ) ; }
static int SnodeWirePacketSendFunction ( ZT_Node * node , void * uptr , void * tptr , const struct sockaddr_storage * localAddr , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl )
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeWirePacketSendFunction ( localAddr , addr , data , len , ttl ) ; }
static int SnodeWirePacketSendFunction ( ZT_Node * node , void * uptr , void * tptr , int64_t localSocket , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl )
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeWirePacketSendFunction ( localSocket , addr , data , len , ttl ) ; }
static void SnodeVirtualNetworkFrameFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t nwid , void * * nuptr , uint64_t sourceMac , uint64_t destMac , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeVirtualNetworkFrameFunction ( nwid , nuptr , sourceMac , destMac , etherType , vlanId , data , len ) ; }
static int SnodePathCheckFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , const struct sockaddr_storage * localAddr , const struct sockaddr_storage * remoteAddr )
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodePathCheckFunction ( ztaddr , localAddr , remoteAddr ) ; }
static int SnodePathCheckFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , int64_t localSocket , const struct sockaddr_storage * remoteAddr )
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodePathCheckFunction ( ztaddr , localSocket , remoteAddr ) ; }
static int SnodePathLookupFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , int family , struct sockaddr_storage * result )
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodePathLookupFunction ( ztaddr , family , result ) ; }
static void StapFrameHandler ( void * uptr , void * tptr , uint64_t nwid , const MAC & from , const MAC & to , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )