2019-07-15 18:57:42 +00:00
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright ( C ) 2011 - 2019 ZeroTier , Inc . https : //www.zerotier.com/
*
* 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/>.
*
* - -
*
* You can be released from the requirements of the license by purchasing
* a commercial license . Buying such a license is mandatory as soon as you
* develop commercial closed - source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application .
*/
2019-08-28 18:49:45 +00:00
# include "../node/Constants.hpp"
2019-07-15 18:57:42 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <fcntl.h>
# include <signal.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/select.h>
# include <sys/time.h>
# include <sys/un.h>
# include <sys/ioctl.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include <netinet/ip.h>
# include <netinet/ip6.h>
# include <netinet/tcp.h>
2019-08-28 18:49:45 +00:00
# include "../node/Packet.hpp"
# include "../node/Utils.hpp"
# include "../node/Address.hpp"
# include "../node/Identity.hpp"
# include "../node/InetAddress.hpp"
# include "../node/Mutex.hpp"
2019-08-28 20:04:58 +00:00
# include "../node/SharedPtr.hpp"
2019-08-28 20:38:52 +00:00
# include "../node/MulticastGroup.hpp"
2019-08-28 18:49:45 +00:00
# include "../osdep/OSUtils.hpp"
2019-07-15 18:57:42 +00:00
# include <string>
# include <thread>
# include <map>
2019-08-28 20:04:58 +00:00
# include <set>
2019-07-15 18:57:42 +00:00
# include <vector>
# include <iostream>
2019-08-28 18:49:45 +00:00
# include <unordered_map>
2019-08-28 22:07:38 +00:00
# include <unordered_set>
2019-08-28 18:49:45 +00:00
# include <vector>
2019-08-28 18:59:13 +00:00
# include <atomic>
2019-08-28 20:04:58 +00:00
# include <mutex>
2019-08-28 18:49:45 +00:00
using namespace ZeroTier ;
2019-08-28 20:38:52 +00:00
struct IdentityHasher { ZT_ALWAYS_INLINE std : : size_t operator ( ) ( const Identity & id ) const { return ( std : : size_t ) id . hashCode ( ) ; } } ;
struct AddressHasher { ZT_ALWAYS_INLINE std : : size_t operator ( ) ( const Address & a ) const { return ( std : : size_t ) a . toInt ( ) ; } } ;
struct InetAddressHasher { ZT_ALWAYS_INLINE std : : size_t operator ( ) ( const InetAddress & ip ) const { return ( std : : size_t ) ip . hashCode ( ) ; } } ;
struct MulticastGroupHasher { ZT_ALWAYS_INLINE std : : size_t operator ( ) ( const MulticastGroup & mg ) const { return ( std : : size_t ) mg . hashCode ( ) ; } } ;
2019-08-29 14:17:18 +00:00
struct RendezvousKey
{
RendezvousKey ( const Address aa , const Address bb )
{
if ( aa > bb ) {
a = aa ;
b = bb ;
} else {
a = bb ;
b = aa ;
}
}
Address a , b ;
ZT_ALWAYS_INLINE bool operator = = ( const RendezvousKey & k ) const { return ( ( a = = k . a ) & & ( b = = k . b ) ) ; }
ZT_ALWAYS_INLINE bool operator ! = ( const RendezvousKey & k ) const { return ( ( a ! = k . a ) | | ( b ! = k . b ) ) ; }
struct Hasher { ZT_ALWAYS_INLINE std : : size_t operator ( ) ( const RendezvousKey & k ) const { return ( std : : size_t ) ( k . a . toInt ( ) ^ k . b . toInt ( ) ) ; } } ;
} ;
struct RootPeer
2019-08-28 18:49:45 +00:00
{
2019-08-28 20:04:58 +00:00
Identity id ;
uint8_t key [ 32 ] ;
InetAddress ip4 , ip6 ;
2019-08-28 18:49:45 +00:00
int64_t lastReceive ;
2019-08-28 22:52:18 +00:00
int64_t lastSync ;
2019-08-28 20:38:52 +00:00
2019-08-28 20:04:58 +00:00
AtomicCounter __refCount ;
2019-08-29 14:17:18 +00:00
ZT_ALWAYS_INLINE ~ RootPeer ( ) { Utils : : burn ( key , sizeof ( key ) ) ; }
2019-08-28 18:49:45 +00:00
} ;
2019-07-15 18:57:42 +00:00
2019-08-28 20:04:58 +00:00
static Identity self ;
2019-08-28 18:59:13 +00:00
static std : : atomic_bool run ;
2019-08-28 20:51:13 +00:00
2019-08-28 22:07:38 +00:00
static std : : unordered_map < uint64_t , std : : unordered_map < MulticastGroup , std : : unordered_map < Address , int64_t , AddressHasher > , MulticastGroupHasher > > multicastSubscriptions ;
2019-08-29 14:17:18 +00:00
static std : : unordered_map < Identity , SharedPtr < RootPeer > , IdentityHasher > peersByIdentity ;
static std : : unordered_map < Address , std : : set < SharedPtr < RootPeer > > , AddressHasher > peersByVirtAddr ;
static std : : unordered_map < InetAddress , std : : set < SharedPtr < RootPeer > > , InetAddressHasher > peersByPhysAddr ;
static std : : unordered_map < RendezvousKey , int64_t , RendezvousKey : : Hasher > lastRendezvous ;
2019-08-28 20:51:13 +00:00
2019-08-28 22:07:38 +00:00
static std : : mutex multicastSubscriptions_l ;
2019-08-28 20:04:58 +00:00
static std : : mutex peersByIdentity_l ;
static std : : mutex peersByVirtAddr_l ;
static std : : mutex peersByPhysAddr_l ;
2019-08-29 14:17:18 +00:00
static std : : mutex lastRendezvous_l ;
2019-08-28 18:49:45 +00:00
2019-08-28 20:59:23 +00:00
static void handlePacket ( const int sock , const InetAddress * const ip , Packet & pkt )
2019-08-28 18:49:45 +00:00
{
2019-08-29 14:17:18 +00:00
char ipstr [ 128 ] , ipstr2 [ 128 ] , astr [ 32 ] , astr2 [ 32 ] , tmpstr [ 256 ] ;
2019-08-28 20:04:58 +00:00
const bool fragment = pkt [ ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR ] = = ZT_PACKET_FRAGMENT_INDICATOR ;
2019-08-29 14:17:18 +00:00
const Address source ( pkt . source ( ) ) ;
const Address dest ( pkt . destination ( ) ) ;
const int64_t now = OSUtils : : now ( ) ;
2019-08-28 20:04:58 +00:00
// See if this is destined for us and isn't a fragment / fragmented. (No packets
// understood by the root are fragments/fragmented.)
2019-08-29 14:17:18 +00:00
if ( ( ! fragment ) & & ( ! pkt . fragmented ( ) ) & & ( dest = = self . address ( ) ) ) {
SharedPtr < RootPeer > peer ;
2019-08-28 20:04:58 +00:00
// If this is an un-encrypted HELLO, either learn a new peer or verify
// that this is a peer we already know.
if ( ( pkt . cipher ( ) = = ZT_PROTO_CIPHER_SUITE__POLY1305_NONE ) & & ( pkt . verb ( ) = = Packet : : VERB_HELLO ) ) {
Identity id ;
if ( id . deserialize ( pkt , ZT_PROTO_VERB_HELLO_IDX_IDENTITY ) ) {
{
std : : lock_guard < std : : mutex > pbi_l ( peersByIdentity_l ) ;
auto pById = peersByIdentity . find ( id ) ;
if ( pById ! = peersByIdentity . end ( ) ) {
peer = pById - > second ;
2019-08-29 14:17:18 +00:00
//printf("%s has %s (known (1))" ZT_EOL_S,ip->toString(ipstr),source().toString(astr));
2019-08-28 20:04:58 +00:00
}
}
if ( peer ) {
if ( ! pkt . dearmor ( peer - > key ) ) {
printf ( " %s HELLO rejected: packet authentication failed " ZT_EOL_S , ip - > toString ( ipstr ) ) ;
return ;
}
} else {
2019-08-29 14:17:18 +00:00
peer . set ( new RootPeer ) ;
2019-08-28 20:10:36 +00:00
if ( self . agree ( id , peer - > key ) ) {
2019-08-28 20:04:58 +00:00
if ( pkt . dearmor ( peer - > key ) ) {
2019-08-28 20:51:13 +00:00
peer - > id = id ;
2019-08-28 22:52:18 +00:00
peer - > lastSync = 0 ;
2019-08-28 20:51:13 +00:00
{
std : : lock_guard < std : : mutex > pbi_l ( peersByIdentity_l ) ;
peersByIdentity . emplace ( id , peer ) ;
}
{
std : : lock_guard < std : : mutex > pbv_l ( peersByVirtAddr_l ) ;
peersByVirtAddr [ id . address ( ) ] . emplace ( peer ) ;
2019-08-28 20:04:58 +00:00
}
} else {
printf ( " %s HELLO rejected: packet authentication failed " ZT_EOL_S , ip - > toString ( ipstr ) ) ;
return ;
}
} else {
printf ( " %s HELLO rejected: key agreement failed " ZT_EOL_S , ip - > toString ( ipstr ) ) ;
return ;
}
}
}
}
// If it wasn't a HELLO, check to see if any known identities for the sender's
// short ZT address successfully decrypt the packet.
if ( ! peer ) {
std : : lock_guard < std : : mutex > pbv_l ( peersByVirtAddr_l ) ;
2019-08-29 14:17:18 +00:00
auto peers = peersByVirtAddr . find ( source ) ;
2019-08-28 20:04:58 +00:00
if ( peers ! = peersByVirtAddr . end ( ) ) {
for ( auto p = peers - > second . begin ( ) ; p ! = peers - > second . end ( ) ; + + p ) {
if ( pkt . dearmor ( ( * p ) - > key ) ) {
peer = ( * p ) ;
2019-08-29 14:17:18 +00:00
//printf("%s has %s (known (2))" ZT_EOL_S,ip->toString(ipstr),source().toString(astr));
2019-08-28 20:04:58 +00:00
break ;
}
}
}
}
// If we found the peer, update IP and/or time.
if ( peer ) {
InetAddress * const peerIp = ( ip - > ss_family = = AF_INET ) ? & ( peer - > ip4 ) : & ( peer - > ip6 ) ;
if ( * peerIp ! = ip ) {
std : : lock_guard < std : : mutex > pbp_l ( peersByPhysAddr_l ) ;
if ( * peerIp ) {
auto prev = peersByPhysAddr . find ( * peerIp ) ;
if ( prev ! = peersByPhysAddr . end ( ) ) {
prev - > second . erase ( peer ) ;
if ( prev - > second . empty ( ) )
peersByPhysAddr . erase ( prev ) ;
}
}
* peerIp = ip ;
peersByPhysAddr [ ip ] . emplace ( peer ) ;
}
2019-08-28 20:38:52 +00:00
const int64_t now = OSUtils : : now ( ) ;
peer - > lastReceive = now ;
switch ( pkt . verb ( ) ) {
2019-08-28 22:20:34 +00:00
case Packet : : VERB_HELLO :
try {
const uint64_t origId = pkt . packetId ( ) ;
const uint64_t ts = pkt . template at < uint64_t > ( ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP ) ;
2019-08-29 14:17:18 +00:00
pkt . reset ( source , self . address ( ) , Packet : : VERB_OK ) ;
2019-08-28 22:20:34 +00:00
pkt . append ( ( uint8_t ) Packet : : VERB_HELLO ) ;
pkt . append ( origId ) ;
pkt . append ( ts ) ;
pkt . append ( ( uint8_t ) ZT_PROTO_VERSION ) ;
pkt . append ( ( uint8_t ) 0 ) ;
pkt . append ( ( uint8_t ) 0 ) ;
pkt . append ( ( uint16_t ) 0 ) ;
ip - > serialize ( pkt ) ;
pkt . armor ( peer - > key , true ) ;
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) ip , ( socklen_t ) ( ( ip - > ss_family = = AF_INET ) ? sizeof ( struct sockaddr_in ) : sizeof ( struct sockaddr_in6 ) ) ) ;
//printf("%s <- OK(HELLO)" ZT_EOL_S,ip->toString(ipstr));
} catch ( . . . ) {
printf ( " * unexpected exception handling HELLO from %s " ZT_EOL_S , ip - > toString ( ipstr ) ) ;
}
break ;
2019-08-28 20:38:52 +00:00
2019-08-28 22:20:34 +00:00
case Packet : : VERB_MULTICAST_LIKE :
try {
std : : lock_guard < std : : mutex > l ( multicastSubscriptions_l ) ;
for ( unsigned int ptr = ZT_PACKET_IDX_PAYLOAD ; ( ptr + 18 ) < = pkt . size ( ) ; ptr + = 18 ) {
const uint64_t nwid = pkt . template at < uint64_t > ( ptr ) ;
const MulticastGroup mg ( MAC ( pkt . field ( ptr + 8 , 6 ) , 6 ) , pkt . template at < uint32_t > ( ptr + 14 ) ) ;
multicastSubscriptions [ nwid ] [ mg ] [ peer - > id . address ( ) ] = now ;
//printf("%s subscribes to %s/%.8lx on network %.16llx" ZT_EOL_S,ip->toString(ipstr),mg.mac().toString(tmpstr),(unsigned long)mg.adi(),(unsigned long long)nwid);
}
} catch ( . . . ) {
printf ( " * unexpected exception handling MULTICAST_LIKE from %s " ZT_EOL_S , ip - > toString ( ipstr ) ) ;
2019-08-28 20:38:52 +00:00
}
2019-08-28 22:20:34 +00:00
break ;
2019-08-28 20:38:52 +00:00
2019-08-28 22:20:34 +00:00
case Packet : : VERB_MULTICAST_GATHER :
try {
const uint64_t nwid = pkt . template at < uint64_t > ( ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID ) ;
const unsigned int flags = pkt [ ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS ] ;
const MulticastGroup mg ( MAC ( pkt . field ( ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC , 6 ) , 6 ) , pkt . template at < uint32_t > ( ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI ) ) ;
unsigned int gatherLimit = pkt . template at < uint32_t > ( ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT ) ;
if ( gatherLimit > 255 )
gatherLimit = 255 ;
2019-08-28 22:07:38 +00:00
2019-08-28 22:20:34 +00:00
const uint64_t origId = pkt . packetId ( ) ;
2019-08-29 14:17:18 +00:00
pkt . reset ( source , self . address ( ) , Packet : : VERB_OK ) ;
2019-08-28 22:20:34 +00:00
pkt . append ( ( uint8_t ) Packet : : VERB_MULTICAST_GATHER ) ;
pkt . append ( origId ) ;
pkt . append ( nwid ) ;
mg . mac ( ) . appendTo ( pkt ) ;
pkt . append ( ( uint32_t ) mg . adi ( ) ) ;
2019-08-28 22:07:38 +00:00
2019-08-28 22:20:34 +00:00
{
std : : lock_guard < std : : mutex > l ( multicastSubscriptions_l ) ;
auto forNet = multicastSubscriptions . find ( nwid ) ;
if ( forNet ! = multicastSubscriptions . end ( ) ) {
auto forGroup = forNet - > second . find ( mg ) ;
if ( forGroup ! = forNet - > second . end ( ) ) {
pkt . append ( ( uint32_t ) forGroup - > second . size ( ) ) ;
pkt . append ( ( uint16_t ) std : : min ( std : : min ( ( unsigned int ) forGroup - > second . size ( ) , ( unsigned int ) 65535 ) , gatherLimit ) ) ;
auto g = forGroup - > second . begin ( ) ;
unsigned int l = 0 ;
for ( ; ( ( l < gatherLimit ) & & ( g ! = forGroup - > second . end ( ) ) ) ; + + l , + + g )
g - > first . appendTo ( pkt ) ;
if ( l > 0 ) {
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) ip , ( socklen_t ) ( ( ip - > ss_family = = AF_INET ) ? sizeof ( struct sockaddr_in ) : sizeof ( struct sockaddr_in6 ) ) ) ;
//printf("%s gathered %u subscribers to %s/%.8lx on network %.16llx" ZT_EOL_S,ip->toString(ipstr),l,mg.mac().toString(tmpstr),(unsigned long)mg.adi(),(unsigned long long)nwid);
}
2019-08-28 22:07:38 +00:00
}
}
}
2019-08-28 22:20:34 +00:00
} catch ( . . . ) {
printf ( " * unexpected exception handling MULTICAST_GATHER from %s " ZT_EOL_S , ip - > toString ( ipstr ) ) ;
2019-08-28 22:07:38 +00:00
}
2019-08-28 22:20:34 +00:00
break ;
2019-08-28 20:38:52 +00:00
default :
break ;
}
2019-08-28 20:04:58 +00:00
return ;
}
}
2019-08-29 14:17:18 +00:00
// If we made it here, we are forwarding this packet to someone else and also possibly
// sending a RENDEZVOUS message.
bool introduce = false ;
{
RendezvousKey rk ( source , dest ) ;
std : : lock_guard < std : : mutex > l ( lastRendezvous_l ) ;
int64_t & lr = lastRendezvous [ rk ] ;
if ( ( now - lr ) > = 45000 ) {
lr = now ;
introduce = true ;
}
}
std : : vector < std : : pair < InetAddress * , SharedPtr < RootPeer > > > toAddrs ;
2019-08-28 20:04:58 +00:00
{
std : : lock_guard < std : : mutex > pbv_l ( peersByVirtAddr_l ) ;
2019-08-29 14:17:18 +00:00
auto peers = peersByVirtAddr . find ( dest ) ;
2019-08-28 20:04:58 +00:00
if ( peers ! = peersByVirtAddr . end ( ) ) {
for ( auto p = peers - > second . begin ( ) ; p ! = peers - > second . end ( ) ; + + p ) {
2019-08-28 22:15:21 +00:00
if ( ( now - ( * p ) - > lastReceive ) < ZT_PEER_ACTIVITY_TIMEOUT ) {
2019-08-29 14:17:18 +00:00
if ( ( * p ) - > ip6 ) {
toAddrs . push_back ( std : : pair < InetAddress * , SharedPtr < RootPeer > > ( & ( ( * p ) - > ip6 ) , * p ) ) ;
} else if ( ( * p ) - > ip4 ) {
toAddrs . push_back ( std : : pair < InetAddress * , SharedPtr < RootPeer > > ( & ( ( * p ) - > ip4 ) , * p ) ) ;
}
2019-08-28 22:15:21 +00:00
}
2019-08-28 20:04:58 +00:00
}
}
}
if ( toAddrs . empty ( ) ) {
2019-08-29 14:17:18 +00:00
//printf("%s not forwarding to %s: no destinations found" ZT_EOL_S,ip->toString(ipstr),dest().toString(astr));
2019-08-28 20:04:58 +00:00
return ;
}
2019-08-29 14:17:18 +00:00
if ( introduce ) {
std : : lock_guard < std : : mutex > l ( peersByVirtAddr_l ) ;
auto sources = peersByVirtAddr . find ( source ) ;
for ( auto a = sources - > second . begin ( ) ; a ! = sources - > second . end ( ) ; + + a ) {
for ( auto b = toAddrs . begin ( ) ; b ! = toAddrs . end ( ) ; + + b ) {
if ( ( ( * a ) - > ip6 = = * ip ) & & ( b - > second - > ip6 ) ) {
printf ( " * introducing %s(%s) to %s(%s) " ZT_EOL_S , ip - > toString ( ipstr ) , source . toString ( astr ) , b - > second - > ip6 . toString ( ipstr2 ) , dest . toString ( astr2 ) ) ;
Packet outp ( source , self . address ( ) , Packet : : VERB_RENDEZVOUS ) ;
outp . append ( ( uint8_t ) 0 ) ;
dest . appendTo ( outp ) ;
outp . append ( ( uint16_t ) b - > second - > ip6 . port ( ) ) ;
outp . append ( ( uint8_t ) 16 ) ;
outp . append ( ( const uint8_t * ) b - > second - > ip6 . rawIpData ( ) , 16 ) ;
outp . armor ( ( * a ) - > key , true ) ;
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) ip , ( socklen_t ) sizeof ( struct sockaddr_in6 ) ) ;
outp . reset ( dest , self . address ( ) , Packet : : VERB_RENDEZVOUS ) ;
outp . append ( ( uint8_t ) 0 ) ;
source . appendTo ( outp ) ;
outp . append ( ( uint16_t ) ip - > port ( ) ) ;
outp . append ( ( uint8_t ) 16 ) ;
outp . append ( ( const uint8_t * ) ip - > rawIpData ( ) , 16 ) ;
outp . armor ( b - > second - > key , true ) ;
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) & ( b - > second - > ip6 ) , ( socklen_t ) sizeof ( struct sockaddr_in6 ) ) ;
} else if ( ( ( * a ) - > ip4 = = * ip ) & & ( b - > second - > ip4 ) ) {
printf ( " * introducing %s(%s) to %s(%s) " ZT_EOL_S , ip - > toString ( ipstr ) , source . toString ( astr ) , b - > second - > ip4 . toString ( ipstr2 ) , dest . toString ( astr2 ) ) ;
Packet outp ( source , self . address ( ) , Packet : : VERB_RENDEZVOUS ) ;
outp . append ( ( uint8_t ) 0 ) ;
dest . appendTo ( outp ) ;
outp . append ( ( uint16_t ) b - > second - > ip4 . port ( ) ) ;
outp . append ( ( uint8_t ) 4 ) ;
outp . append ( ( const uint8_t * ) b - > second - > ip4 . rawIpData ( ) , 4 ) ;
outp . armor ( ( * a ) - > key , true ) ;
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) ip , ( socklen_t ) sizeof ( struct sockaddr_in ) ) ;
outp . reset ( dest , self . address ( ) , Packet : : VERB_RENDEZVOUS ) ;
outp . append ( ( uint8_t ) 0 ) ;
source . appendTo ( outp ) ;
outp . append ( ( uint16_t ) ip - > port ( ) ) ;
outp . append ( ( uint8_t ) 4 ) ;
outp . append ( ( const uint8_t * ) ip - > rawIpData ( ) , 4 ) ;
outp . armor ( b - > second - > key , true ) ;
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) & ( b - > second - > ip4 ) , ( socklen_t ) sizeof ( struct sockaddr_in ) ) ;
}
}
}
}
2019-08-28 20:04:58 +00:00
if ( fragment ) {
if ( reinterpret_cast < Packet : : Fragment * > ( & pkt ) - > incrementHops ( ) > = ZT_PROTO_MAX_HOPS ) {
2019-08-29 14:17:18 +00:00
printf ( " %s refused to forward to %s: max hop count exceeded " ZT_EOL_S , ip - > toString ( ipstr ) , dest . toString ( astr ) ) ;
2019-08-28 20:04:58 +00:00
return ;
}
} else {
if ( pkt . incrementHops ( ) > = ZT_PROTO_MAX_HOPS ) {
2019-08-29 14:17:18 +00:00
printf ( " %s refused to forward to %s: max hop count exceeded " ZT_EOL_S , ip - > toString ( ipstr ) , dest . toString ( astr ) ) ;
2019-08-28 20:04:58 +00:00
return ;
}
}
for ( auto i = toAddrs . begin ( ) ; i ! = toAddrs . end ( ) ; + + i ) {
2019-08-29 14:17:18 +00:00
//printf("%s -> %s for %s" ZT_EOL_S,ip->toString(ipstr),i->toString(ipstr2),dest().toString(astr));
sendto ( sock , pkt . data ( ) , pkt . size ( ) , 0 , ( const struct sockaddr * ) i - > first , ( socklen_t ) ( ( i - > first - > ss_family = = AF_INET ) ? sizeof ( struct sockaddr_in ) : sizeof ( struct sockaddr_in6 ) ) ) ;
2019-08-28 20:04:58 +00:00
}
2019-08-28 18:49:45 +00:00
}
2019-07-15 18:57:42 +00:00
static int bindSocket ( struct sockaddr * bindAddr )
{
int s = socket ( bindAddr - > sa_family , SOCK_DGRAM , 0 ) ;
if ( s < 0 ) {
close ( s ) ;
return - 1 ;
}
int f = 131072 ;
setsockopt ( s , SOL_SOCKET , SO_RCVBUF , ( const char * ) & f , sizeof ( f ) ) ;
f = 131072 ;
setsockopt ( s , SOL_SOCKET , SO_SNDBUF , ( const char * ) & f , sizeof ( f ) ) ;
if ( bindAddr - > sa_family = = AF_INET6 ) {
f = 1 ; setsockopt ( s , IPPROTO_IPV6 , IPV6_V6ONLY , ( void * ) & f , sizeof ( f ) ) ;
# ifdef IPV6_MTU_DISCOVER
f = 0 ; setsockopt ( s , IPPROTO_IPV6 , IPV6_MTU_DISCOVER , & f , sizeof ( f ) ) ;
# endif
# ifdef IPV6_DONTFRAG
f = 0 ; setsockopt ( s , IPPROTO_IPV6 , IPV6_DONTFRAG , & f , sizeof ( f ) ) ;
# endif
}
f = 1 ; setsockopt ( s , SOL_SOCKET , SO_REUSEADDR , ( void * ) & f , sizeof ( f ) ) ;
f = 1 ; setsockopt ( s , SOL_SOCKET , SO_REUSEPORT , ( void * ) & f , sizeof ( f ) ) ;
f = 1 ; setsockopt ( s , SOL_SOCKET , SO_BROADCAST , ( void * ) & f , sizeof ( f ) ) ;
# ifdef IP_DONTFRAG
f = 0 ; setsockopt ( s , IPPROTO_IP , IP_DONTFRAG , & f , sizeof ( f ) ) ;
# endif
# ifdef IP_MTU_DISCOVER
f = IP_PMTUDISC_DONT ; setsockopt ( s , IPPROTO_IP , IP_MTU_DISCOVER , & f , sizeof ( f ) ) ;
# endif
# ifdef SO_NO_CHECK
if ( bindAddr - > sa_family = = AF_INET ) {
f = 1 ; setsockopt ( s , SOL_SOCKET , SO_NO_CHECK , ( void * ) & f , sizeof ( f ) ) ;
}
# endif
if ( bind ( s , bindAddr , ( bindAddr - > sa_family = = AF_INET ) ? sizeof ( struct sockaddr_in ) : sizeof ( struct sockaddr_in6 ) ) ) {
close ( s ) ;
return - 1 ;
}
return s ;
}
2019-08-28 21:04:42 +00:00
void shutdownSigHandler ( int sig )
{
run = false ;
}
2019-07-15 18:57:42 +00:00
int main ( int argc , char * * argv )
{
2019-08-28 21:04:42 +00:00
signal ( SIGTERM , shutdownSigHandler ) ;
signal ( SIGINT , shutdownSigHandler ) ;
signal ( SIGQUIT , shutdownSigHandler ) ;
signal ( SIGPIPE , SIG_IGN ) ;
signal ( SIGUSR1 , SIG_IGN ) ;
signal ( SIGUSR2 , SIG_IGN ) ;
2019-08-28 20:10:36 +00:00
if ( argc < 2 ) {
2019-08-28 20:09:14 +00:00
printf ( " Usage: zerotier-root <identity.secret> [<port>] " ZT_EOL_S ) ;
return 1 ;
}
std : : string myIdStr ;
if ( ! OSUtils : : readFile ( argv [ 1 ] , myIdStr ) ) {
printf ( " FATAL: cannot read identity.secret at %s " ZT_EOL_S , argv [ 1 ] ) ;
return 1 ;
}
if ( ! self . fromString ( myIdStr . c_str ( ) ) ) {
printf ( " FATAL: cannot read identity.secret at %s (invalid identity) " ZT_EOL_S , argv [ 1 ] ) ;
return 1 ;
}
if ( ! self . hasPrivate ( ) ) {
printf ( " FATAL: cannot read identity.secret at %s (missing secret key) " ZT_EOL_S , argv [ 1 ] ) ;
return 1 ;
}
2019-07-15 18:57:42 +00:00
unsigned int ncores = std : : thread : : hardware_concurrency ( ) ;
if ( ncores = = 0 ) ncores = 1 ;
2019-08-28 18:59:13 +00:00
run = true ;
2019-07-15 18:57:42 +00:00
std : : vector < std : : thread > threads ;
2019-08-28 22:15:21 +00:00
std : : vector < int > sockets ;
2019-07-15 18:57:42 +00:00
for ( unsigned int tn = 0 ; tn < ncores ; + + tn ) {
struct sockaddr_in6 in6 ;
memset ( & in6 , 0 , sizeof ( in6 ) ) ;
in6 . sin6_family = AF_INET6 ;
in6 . sin6_port = htons ( ZT_DEFAULT_PORT ) ;
const int s6 = bindSocket ( ( struct sockaddr * ) & in6 ) ;
if ( s6 < 0 ) {
std : : cout < < " ERROR: unable to bind to port " < < ZT_DEFAULT_PORT < < ZT_EOL_S ;
exit ( 1 ) ;
}
struct sockaddr_in in4 ;
memset ( & in4 , 0 , sizeof ( in4 ) ) ;
in4 . sin_family = AF_INET ;
in4 . sin_port = htons ( ZT_DEFAULT_PORT ) ;
const int s4 = bindSocket ( ( struct sockaddr * ) & in4 ) ;
if ( s4 < 0 ) {
std : : cout < < " ERROR: unable to bind to port " < < ZT_DEFAULT_PORT < < ZT_EOL_S ;
exit ( 1 ) ;
}
sockets . push_back ( s6 ) ;
sockets . push_back ( s4 ) ;
threads . push_back ( std : : thread ( [ s6 ] ( ) {
struct sockaddr_in6 in6 ;
2019-08-28 18:49:45 +00:00
Packet pkt ;
2019-07-15 18:57:42 +00:00
memset ( & in6 , 0 , sizeof ( in6 ) ) ;
for ( ; ; ) {
socklen_t sl = sizeof ( in6 ) ;
2019-08-28 18:49:45 +00:00
const int pl = ( int ) recvfrom ( s6 , pkt . unsafeData ( ) , pkt . capacity ( ) , 0 , ( struct sockaddr * ) & in6 , & sl ) ;
2019-07-15 18:57:42 +00:00
if ( pl > 0 ) {
2019-08-28 22:22:28 +00:00
if ( pl > = ZT_PROTO_MIN_FRAGMENT_LENGTH ) {
try {
pkt . setSize ( ( unsigned int ) pl ) ;
handlePacket ( s6 , reinterpret_cast < const InetAddress * > ( & in6 ) , pkt ) ;
} catch ( . . . ) {
char ipstr [ 128 ] ;
printf ( " * unexpected exception handling packet from %s " ZT_EOL_S , reinterpret_cast < const InetAddress * > ( & in6 ) - > toString ( ipstr ) ) ;
}
2019-08-28 18:49:45 +00:00
}
} else {
break ;
}
2019-07-15 18:57:42 +00:00
}
} ) ) ;
threads . push_back ( std : : thread ( [ s4 ] ( ) {
struct sockaddr_in in4 ;
2019-08-28 18:49:45 +00:00
Packet pkt ;
2019-07-15 18:57:42 +00:00
memset ( & in4 , 0 , sizeof ( in4 ) ) ;
for ( ; ; ) {
socklen_t sl = sizeof ( in4 ) ;
2019-08-28 18:49:45 +00:00
const int pl = ( int ) recvfrom ( s4 , pkt . unsafeData ( ) , pkt . capacity ( ) , 0 , ( struct sockaddr * ) & in4 , & sl ) ;
2019-07-15 18:57:42 +00:00
if ( pl > 0 ) {
2019-08-28 22:22:28 +00:00
if ( pl > = ZT_PROTO_MIN_FRAGMENT_LENGTH ) {
try {
pkt . setSize ( ( unsigned int ) pl ) ;
handlePacket ( s4 , reinterpret_cast < const InetAddress * > ( & in4 ) , pkt ) ;
} catch ( . . . ) {
char ipstr [ 128 ] ;
printf ( " * unexpected exception handling packet from %s " ZT_EOL_S , reinterpret_cast < const InetAddress * > ( & in4 ) - > toString ( ipstr ) ) ;
}
2019-08-28 18:49:45 +00:00
}
} else {
break ;
}
2019-07-15 18:57:42 +00:00
}
} ) ) ;
}
2019-08-28 22:15:21 +00:00
int64_t lastCleanedMulticastSubscriptions = 0 ;
2019-08-28 22:52:18 +00:00
int64_t lastCleanedPeers = 0 ;
2019-08-28 18:59:13 +00:00
while ( run ) {
2019-08-28 20:51:13 +00:00
peersByIdentity_l . lock ( ) ;
2019-08-28 22:15:21 +00:00
peersByPhysAddr_l . lock ( ) ;
printf ( " *** have %lu peers at %lu physical endpoints " ZT_EOL_S , ( unsigned long ) peersByIdentity . size ( ) , ( unsigned long ) peersByPhysAddr . size ( ) ) ;
peersByPhysAddr_l . unlock ( ) ;
2019-08-28 20:51:13 +00:00
peersByIdentity_l . unlock ( ) ;
2019-08-28 18:59:13 +00:00
sleep ( 1 ) ;
2019-08-28 22:15:21 +00:00
const int64_t now = OSUtils : : now ( ) ;
2019-08-28 22:52:18 +00:00
2019-08-28 22:15:21 +00:00
if ( ( now - lastCleanedMulticastSubscriptions ) > 120000 ) {
lastCleanedMulticastSubscriptions = now ;
2019-08-28 22:52:18 +00:00
2019-08-28 22:15:21 +00:00
std : : lock_guard < std : : mutex > l ( multicastSubscriptions_l ) ;
for ( auto a = multicastSubscriptions . begin ( ) ; a ! = multicastSubscriptions . end ( ) ; ) {
for ( auto b = a - > second . begin ( ) ; b ! = a - > second . end ( ) ; ) {
for ( auto c = b - > second . begin ( ) ; c ! = b - > second . end ( ) ; ) {
if ( ( now - c - > second ) > ZT_MULTICAST_LIKE_EXPIRE )
b - > second . erase ( c + + ) ;
else + + c ;
}
if ( b - > second . empty ( ) )
a - > second . erase ( b + + ) ;
else + + b ;
}
if ( a - > second . empty ( ) )
multicastSubscriptions . erase ( a + + ) ;
else + + a ;
}
}
2019-08-28 22:52:18 +00:00
if ( ( now - lastCleanedPeers ) > 120000 ) {
lastCleanedPeers = now ;
std : : lock_guard < std : : mutex > pbi_l ( peersByIdentity_l ) ;
for ( auto p = peersByIdentity . begin ( ) ; p ! = peersByIdentity . end ( ) ; ) {
if ( ( now - p - > second - > lastReceive ) > ZT_PEER_ACTIVITY_TIMEOUT ) {
std : : lock_guard < std : : mutex > pbv_l ( peersByVirtAddr_l ) ;
std : : lock_guard < std : : mutex > pbp_l ( peersByPhysAddr_l ) ;
auto pbv = peersByVirtAddr . find ( p - > second - > id . address ( ) ) ;
if ( pbv ! = peersByVirtAddr . end ( ) ) {
pbv - > second . erase ( p - > second ) ;
if ( pbv - > second . empty ( ) )
peersByVirtAddr . erase ( pbv ) ;
}
if ( p - > second - > ip4 ) {
auto pbp = peersByPhysAddr . find ( p - > second - > ip4 ) ;
if ( pbp ! = peersByPhysAddr . end ( ) ) {
pbp - > second . erase ( p - > second ) ;
if ( pbp - > second . empty ( ) )
peersByPhysAddr . erase ( pbp ) ;
}
}
if ( p - > second - > ip6 ) {
auto pbp = peersByPhysAddr . find ( p - > second - > ip6 ) ;
if ( pbp ! = peersByPhysAddr . end ( ) ) {
pbp - > second . erase ( p - > second ) ;
if ( pbp - > second . empty ( ) )
peersByPhysAddr . erase ( pbp ) ;
}
}
peersByIdentity . erase ( p + + ) ;
} else + + p ;
}
}
2019-08-28 18:59:13 +00:00
}
2019-08-28 21:06:45 +00:00
for ( auto s = sockets . begin ( ) ; s ! = sockets . end ( ) ; + + s ) {
shutdown ( * s , SHUT_RDWR ) ;
close ( * s ) ;
}
for ( auto t = threads . begin ( ) ; t ! = threads . end ( ) ; + + t )
t - > join ( ) ;
2019-07-15 18:57:42 +00:00
return 0 ;
}