2015-04-10 01:14:27 +00:00
/*
2020-05-12 08:35:48 +00:00
* Copyright ( c ) 2013 - 2020 ZeroTier , Inc .
2015-04-10 01:14:27 +00:00
*
2019-08-23 16:23:39 +00:00
* Use of this software is governed by the Business Source License included
* in the LICENSE . TXT file in the project ' s root directory .
2015-04-10 01:14:27 +00:00
*
2020-08-20 19:51:39 +00:00
* Change Date : 2025 - 01 - 01
2015-04-10 01:14:27 +00:00
*
2019-08-23 16:23:39 +00:00
* On the date above , in accordance with the Business Source License , use
* of this software will be governed by version 2.0 of the Apache License .
2015-04-10 01:14:27 +00:00
*/
2019-08-23 16:23:39 +00:00
/****/
2015-04-10 01:14:27 +00:00
2023-04-28 18:03:28 +00:00
# include <exception>
2015-04-10 01:14:27 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2015-05-21 02:38:49 +00:00
# include <stdint.h>
2015-04-10 01:14:27 +00:00
2015-04-11 00:07:06 +00:00
# include <string>
# include <map>
# include <vector>
# include <algorithm>
2016-06-15 22:46:57 +00:00
# include <list>
2018-11-12 06:35:15 +00:00
# include <thread>
# include <mutex>
# include <condition_variable>
2015-04-11 00:07:06 +00:00
2015-04-10 01:14:27 +00:00
# include "../version.h"
# include "../include/ZeroTierOne.h"
# include "../node/Constants.hpp"
# include "../node/Mutex.hpp"
# include "../node/Node.hpp"
# include "../node/Utils.hpp"
# include "../node/InetAddress.hpp"
2015-04-15 00:57:51 +00:00
# include "../node/MAC.hpp"
2015-05-21 02:38:49 +00:00
# include "../node/Identity.hpp"
2017-03-07 21:53:11 +00:00
# include "../node/World.hpp"
2017-06-05 19:15:28 +00:00
# include "../node/Salsa20.hpp"
# include "../node/Poly1305.hpp"
# include "../node/SHA512.hpp"
2020-05-12 08:35:48 +00:00
# include "../node/Bond.hpp"
# include "../node/Peer.hpp"
2015-04-10 01:14:27 +00:00
# include "../osdep/Phy.hpp"
# include "../osdep/OSUtils.hpp"
2015-05-21 02:38:49 +00:00
# include "../osdep/Http.hpp"
2015-11-30 21:10:22 +00:00
# include "../osdep/PortMapper.hpp"
2016-04-05 18:59:46 +00:00
# include "../osdep/Binder.hpp"
2016-06-15 22:46:57 +00:00
# include "../osdep/ManagedRoute.hpp"
2018-11-13 20:07:58 +00:00
# include "../osdep/BlockingQueue.hpp"
2015-04-10 01:14:27 +00:00
2015-04-15 21:42:26 +00:00
# include "OneService.hpp"
2017-01-12 00:34:33 +00:00
# include "SoftwareUpdater.hpp"
2015-05-17 22:51:07 +00:00
2023-04-28 18:03:28 +00:00
# include <cpp-httplib/httplib.h>
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-11-18 20:39:55 +00:00
# include <zeroidc.h>
2022-02-01 19:07:37 +00:00
# endif
2021-11-18 20:39:55 +00:00
2015-04-24 22:05:28 +00:00
# ifdef __WINDOWS__
2021-12-27 19:07:35 +00:00
# include <winsock2.h>
# include <windows.h>
# include <shlobj.h>
2015-07-07 00:22:37 +00:00
# include <netioapi.h>
# include <iphlpapi.h>
2018-10-23 20:21:25 +00:00
//#include <unistd.h>
2018-09-11 23:55:46 +00:00
# define stat _stat
2015-05-21 02:38:49 +00:00
# else
# include <sys/types.h>
2015-07-06 23:32:34 +00:00
# include <sys/socket.h>
2018-09-11 23:55:46 +00:00
# include <sys/stat.h>
2015-05-21 02:38:49 +00:00
# include <sys/wait.h>
# include <unistd.h>
2015-07-06 23:32:34 +00:00
# include <ifaddrs.h>
2015-04-24 22:05:28 +00:00
# endif
2020-09-10 22:59:18 +00:00
# ifdef __APPLE__
# include "../osdep/MacDNSHelper.hpp"
# elif defined(__WINDOWS__)
# include "../osdep/WinDNSHelper.hpp"
2022-12-19 21:26:29 +00:00
# include "../osdep/WinFWHelper.hpp"
2020-09-10 22:59:18 +00:00
# endif
2016-11-21 21:20:56 +00:00
# ifdef ZT_USE_SYSTEM_HTTP_PARSER
# include <http_parser.h>
# else
# include "../ext/http-parser/http_parser.h"
# endif
2023-04-21 19:12:43 +00:00
# include "../node/Metrics.hpp"
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
extern " C " {
# include <curl/curl.h>
}
# endif
2022-05-13 16:34:15 +00:00
# include <nlohmann/json.hpp>
# include <inja/inja.hpp>
2016-11-21 21:20:56 +00:00
using json = nlohmann : : json ;
2016-08-17 17:42:32 +00:00
# include "../controller/EmbeddedNetworkController.hpp"
2020-05-11 22:03:56 +00:00
# include "../controller/PostgreSQL.hpp"
# include "../controller/Redis.hpp"
2019-08-07 23:20:17 +00:00
# include "../osdep/EthernetTap.hpp"
2019-08-08 19:08:35 +00:00
# ifdef __WINDOWS__
# include "../osdep/WindowsEthernetTap.hpp"
# endif
2015-12-22 00:15:39 +00:00
2019-06-19 17:19:59 +00:00
# ifndef ZT_SOFTWARE_UPDATE_DEFAULT
# define ZT_SOFTWARE_UPDATE_DEFAULT "disable"
# endif
2015-04-11 02:08:49 +00:00
// Sanity limits for HTTP
2015-06-04 00:20:30 +00:00
# define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 64)
2017-04-26 15:42:49 +00:00
# define ZT_MAX_HTTP_CONNECTIONS 65536
2015-04-11 02:08:49 +00:00
2016-04-05 22:44:08 +00:00
// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also
// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi.
2016-04-01 18:07:44 +00:00
# define ZT_IF_METRIC 5000
2015-04-15 00:57:51 +00:00
// How often to check for new multicast subscriptions on a tap device
2015-12-22 00:15:39 +00:00
# define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000
2015-04-15 00:57:51 +00:00
2017-01-26 21:59:20 +00:00
// TCP fallback relay (run by ZeroTier, Inc. -- this will eventually go away)
2019-01-14 19:34:46 +00:00
# ifndef ZT_SDK
2017-01-26 21:59:20 +00:00
# define ZT_TCP_FALLBACK_RELAY "204.80.128.1 / 443"
2019-01-14 19:34:46 +00:00
# endif
2015-05-21 22:22:41 +00:00
// Frequency at which we re-resolve the TCP fallback relay
2015-09-24 23:21:36 +00:00
# define ZT_TCP_FALLBACK_RERESOLVE_DELAY 86400000
2015-05-21 22:22:41 +00:00
2015-05-22 01:33:52 +00:00
// Attempt to engage TCP fallback after this many ms of no reply to packets sent to global-scope IPs
2015-09-24 23:21:36 +00:00
# define ZT_TCP_FALLBACK_AFTER 60000
2015-05-22 01:33:52 +00:00
2015-07-06 23:32:34 +00:00
// How often to check for local interface addresses
2016-04-07 19:13:18 +00:00
# define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000
2015-07-06 23:32:34 +00:00
2017-06-05 19:15:28 +00:00
// Maximum write buffer size for outgoing TCP connections (sanity limit)
# define ZT_TCP_MAX_WRITEQ_SIZE 33554432
2015-05-21 02:38:49 +00:00
2017-06-05 19:15:28 +00:00
// TCP activity timeout
# define ZT_TCP_ACTIVITY_TIMEOUT 60000
2015-05-21 02:38:49 +00:00
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
size_t curlResponseWrite ( void * ptr , size_t size , size_t nmemb , std : : string * data )
{
data - > append ( ( char * ) ptr , size * nmemb ) ;
return size * nmemb ;
}
# endif
2022-03-10 20:59:26 +00:00
2015-04-10 01:14:27 +00:00
namespace ZeroTier {
2015-12-01 00:44:32 +00:00
2022-05-13 23:18:34 +00:00
std : : string ssoResponseTemplate = R " " " (
< ! doctype html >
< html class = " no - js " lang= " " >
< head >
< meta charset = " utf-8 " >
< meta http - equiv = " x-ua-compatible " content = " ie=edge " >
< title > Network SSO Login { { networkId } } < / title >
< meta name = " description " content = " " >
< meta name = " viewport " content = " width=device-width, initial-scale=1 " >
2022-06-08 16:26:37 +00:00
< style type = " text/css " >
2022-05-13 23:18:34 +00:00
html , body {
background : # eeeeee ;
margin : 0 ;
padding : 0 ;
2022-06-08 23:17:28 +00:00
font - family : " System Sans Serif " ;
font - weight : normal ;
2022-05-13 23:18:34 +00:00
font - size : 12 pt ;
height : 100 % ;
width : 100 % ;
}
2022-06-08 23:17:28 +00:00
2022-05-13 23:18:34 +00:00
. container {
2022-06-08 23:17:28 +00:00
position : absolute ;
left : 50 % ;
top : 50 % ;
- webkit - transform : translate ( - 50 % , - 50 % ) ;
transform : translate ( - 50 % , - 50 % ) ;
}
. iconwrapper {
margin : 10 px 10 px 10 px 10 px ;
2022-05-13 23:18:34 +00:00
}
< / style >
< / head >
< body >
< div class = " container " >
2022-06-08 23:17:28 +00:00
< div class = " iconwrapper " >
< svg id = " Layer_1 " width = " 225px " height = " 225px " data - name = " Layer 1 " xmlns = " http://www.w3.org/2000/svg " viewBox = " 0 0 225 225 " > < defs > < style > . cls - 1 { fill : # fdb25d ; } . cls - 2 { fill : none ; stroke : # 000 ; stroke - miterlimit : 10 ; stroke - width : 6.99 px ; } < / style > < / defs > < rect class = " cls - 1 " width= " 225 " height= " 225 " rx= " 35.74 " /><line class= " cls - 2 " x1= " 25.65 " y1= " 32.64 " x2= " 199.35 " y2= " 32.64 " /><line class= " cls - 2 " x1= " 112.5 " y1= " 201.02 " x2= " 112.5 " y2= " 32.64 " /><circle class= " cls - 2 " cx= " 112.5 " cy= " 115.22 " r= " 56.54 " /></svg>
< / div >
2022-05-13 23:18:34 +00:00
< div class = " text " >{{ messageText }}</div>
< / div >
< / body >
< / html >
) " " " ;
2022-03-10 20:59:26 +00:00
2023-04-28 18:03:28 +00:00
# if ZT_DEBUG==1
std : : string dump_headers ( const httplib : : Headers & headers ) {
std : : string s ;
char buf [ BUFSIZ ] ;
for ( auto it = headers . begin ( ) ; it ! = headers . end ( ) ; + + it ) {
const auto & x = * it ;
snprintf ( buf , sizeof ( buf ) , " %s: %s \n " , x . first . c_str ( ) , x . second . c_str ( ) ) ;
s + = buf ;
}
return s ;
}
std : : string http_log ( const httplib : : Request & req , const httplib : : Response & res ) {
std : : string s ;
char buf [ BUFSIZ ] ;
s + = " ================================ \n " ;
snprintf ( buf , sizeof ( buf ) , " %s %s %s " , req . method . c_str ( ) ,
req . version . c_str ( ) , req . path . c_str ( ) ) ;
s + = buf ;
std : : string query ;
for ( auto it = req . params . begin ( ) ; it ! = req . params . end ( ) ; + + it ) {
const auto & x = * it ;
snprintf ( buf , sizeof ( buf ) , " %c%s=%s " ,
( it = = req . params . begin ( ) ) ? ' ? ' : ' & ' , x . first . c_str ( ) ,
x . second . c_str ( ) ) ;
query + = buf ;
}
snprintf ( buf , sizeof ( buf ) , " %s \n " , query . c_str ( ) ) ;
s + = buf ;
s + = dump_headers ( req . headers ) ;
s + = " -------------------------------- \n " ;
snprintf ( buf , sizeof ( buf ) , " %d %s \n " , res . status , res . version . c_str ( ) ) ;
s + = buf ;
s + = dump_headers ( res . headers ) ;
s + = " \n " ;
if ( ! res . body . empty ( ) ) { s + = res . body ; }
s + = " \n " ;
return s ;
}
# endif
2021-11-29 22:11:29 +00:00
// Configured networks
class NetworkState
{
public :
NetworkState ( )
: _webPort ( 9993 )
, _tap ( ( EthernetTap * ) 0 )
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-11-29 22:11:29 +00:00
, _idc ( nullptr )
2022-02-03 18:07:07 +00:00
# endif
2021-11-29 22:11:29 +00:00
{
// Real defaults are in network 'up' code in network event handler
_settings . allowManaged = true ;
_settings . allowGlobal = false ;
_settings . allowDefault = false ;
_settings . allowDNS = false ;
memset ( & _config , 0 , sizeof ( ZT_VirtualNetworkConfig ) ) ;
}
~ NetworkState ( )
{
this - > _managedRoutes . clear ( ) ;
this - > _tap . reset ( ) ;
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-11-29 22:11:29 +00:00
if ( _idc ) {
zeroidc : : zeroidc_stop ( _idc ) ;
zeroidc : : zeroidc_delete ( _idc ) ;
_idc = nullptr ;
}
2022-02-01 19:07:37 +00:00
# endif
2021-11-29 22:11:29 +00:00
}
void setWebPort ( unsigned int port ) {
_webPort = port ;
}
void setTap ( std : : shared_ptr < EthernetTap > tap ) {
this - > _tap = tap ;
}
std : : shared_ptr < EthernetTap > tap ( ) const {
return _tap ;
}
OneService : : NetworkSettings settings ( ) const {
return _settings ;
}
void setSettings ( const OneService : : NetworkSettings & settings ) {
_settings = settings ;
}
void setAllowManaged ( bool allow ) {
_settings . allowManaged = allow ;
}
bool allowManaged ( ) const {
return _settings . allowManaged ;
}
void setAllowGlobal ( bool allow ) {
_settings . allowGlobal = allow ;
}
bool allowGlobal ( ) const {
return _settings . allowGlobal ;
}
void setAllowDefault ( bool allow ) {
_settings . allowDefault = allow ;
}
bool allowDefault ( ) const {
return _settings . allowDefault ;
}
void setAllowDNS ( bool allow ) {
_settings . allowDNS = allow ;
}
bool allowDNS ( ) const {
return _settings . allowDNS ;
}
std : : vector < InetAddress > allowManagedWhitelist ( ) const {
return _settings . allowManagedWhitelist ;
}
void addToAllowManagedWhiteList ( const InetAddress & addr ) {
_settings . allowManagedWhitelist . push_back ( addr ) ;
}
const ZT_VirtualNetworkConfig & config ( ) {
return _config ;
}
void setConfig ( const ZT_VirtualNetworkConfig * nwc ) {
memcpy ( & _config , nwc , sizeof ( ZT_VirtualNetworkConfig ) ) ;
2021-12-01 01:27:13 +00:00
2021-11-29 22:11:29 +00:00
if ( _config . ssoEnabled & & _config . ssoVersion = = 1 ) {
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-11-30 22:22:25 +00:00
if ( _idc = = nullptr )
{
assert ( _config . issuerURL ! = nullptr ) ;
2021-11-29 22:11:29 +00:00
assert ( _config . ssoClientID ! = nullptr ) ;
assert ( _config . centralAuthURL ! = nullptr ) ;
2023-01-19 23:39:15 +00:00
assert ( _config . ssoProvider ! = nullptr ) ;
2021-12-01 01:27:13 +00:00
2021-11-29 22:11:29 +00:00
_idc = zeroidc : : zeroidc_new (
_config . issuerURL ,
_config . ssoClientID ,
_config . centralAuthURL ,
2023-01-19 23:39:15 +00:00
_config . ssoProvider ,
2021-11-29 22:11:29 +00:00
_webPort
) ;
2021-11-30 22:22:25 +00:00
2021-12-01 18:44:29 +00:00
if ( _idc = = nullptr ) {
fprintf ( stderr , " idc is null \n " ) ;
return ;
}
2021-11-29 22:11:29 +00:00
}
2021-12-15 22:16:17 +00:00
zeroidc : : zeroidc_set_nonce_and_csrf (
2021-11-29 22:11:29 +00:00
_idc ,
_config . ssoState ,
_config . ssoNonce
) ;
2022-04-15 16:15:44 +00:00
char * url = zeroidc : : zeroidc_get_auth_url ( _idc ) ;
2021-11-29 22:11:29 +00:00
memcpy ( _config . authenticationURL , url , strlen ( url ) ) ;
_config . authenticationURL [ strlen ( url ) ] = 0 ;
2022-04-15 16:15:44 +00:00
zeroidc : : free_cstr ( url ) ;
2022-01-20 17:44:56 +00:00
if ( zeroidc : : zeroidc_is_running ( _idc ) & & nwc - > status = = ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED ) {
zeroidc : : zeroidc_kick_refresh_thread ( _idc ) ;
}
2022-02-01 19:07:37 +00:00
# endif
2021-11-29 22:11:29 +00:00
}
}
std : : vector < InetAddress > & managedIps ( ) {
return _managedIps ;
}
void setManagedIps ( const std : : vector < InetAddress > & managedIps ) {
_managedIps = managedIps ;
}
std : : map < InetAddress , SharedPtr < ManagedRoute > > & managedRoutes ( ) {
return _managedRoutes ;
}
2021-11-30 22:22:25 +00:00
const char * getAuthURL ( ) {
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-12-15 22:16:17 +00:00
if ( _idc ! = nullptr ) {
return zeroidc : : zeroidc_get_auth_url ( _idc ) ;
2021-11-30 22:22:25 +00:00
}
2021-12-15 22:16:17 +00:00
fprintf ( stderr , " _idc is null \n " ) ;
2022-02-01 19:07:37 +00:00
# endif
2021-11-30 22:22:25 +00:00
return " " ;
}
2022-04-15 16:15:44 +00:00
char * doTokenExchange ( const char * code ) {
2022-05-13 04:04:16 +00:00
char * ret = nullptr ;
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-12-15 22:16:17 +00:00
if ( _idc = = nullptr ) {
2021-12-02 00:57:18 +00:00
fprintf ( stderr , " ainfo or idc null \n " ) ;
2022-05-13 16:51:37 +00:00
return ret ;
2021-12-02 00:57:18 +00:00
}
2022-05-13 04:04:16 +00:00
ret = zeroidc : : zeroidc_token_exchange ( _idc , code ) ;
2021-12-15 22:16:17 +00:00
zeroidc : : zeroidc_set_nonce_and_csrf (
2021-12-02 00:57:18 +00:00
_idc ,
_config . ssoState ,
_config . ssoNonce
) ;
2022-04-15 16:15:44 +00:00
char * url = zeroidc : : zeroidc_get_auth_url ( _idc ) ;
2021-12-02 00:57:18 +00:00
memcpy ( _config . authenticationURL , url , strlen ( url ) ) ;
_config . authenticationURL [ strlen ( url ) ] = 0 ;
2022-04-15 16:15:44 +00:00
zeroidc : : free_cstr ( url ) ;
2022-02-01 19:07:37 +00:00
# endif
2022-05-13 04:04:16 +00:00
return ret ;
2021-12-02 00:57:18 +00:00
}
2021-12-03 19:32:29 +00:00
uint64_t getExpiryTime ( ) {
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-12-03 19:32:29 +00:00
if ( _idc = = nullptr ) {
fprintf ( stderr , " idc is null \n " ) ;
return 0 ;
}
return zeroidc : : zeroidc_get_exp_time ( _idc ) ;
2022-02-01 19:07:37 +00:00
# else
return 0 ;
# endif
2021-12-03 19:32:29 +00:00
}
2021-11-29 22:11:29 +00:00
private :
unsigned int _webPort ;
std : : shared_ptr < EthernetTap > _tap ;
ZT_VirtualNetworkConfig _config ; // memcpy() of raw config from core
std : : vector < InetAddress > _managedIps ;
std : : map < InetAddress , SharedPtr < ManagedRoute > > _managedRoutes ;
OneService : : NetworkSettings _settings ;
2022-04-01 04:45:38 +00:00
# if ZT_SSO_ENABLED
2021-11-29 22:11:29 +00:00
zeroidc : : ZeroIDC * _idc ;
2022-02-01 19:07:37 +00:00
# endif
2021-11-29 22:11:29 +00:00
} ;
2015-05-20 23:35:33 +00:00
namespace {
2015-12-01 00:44:32 +00:00
2019-06-13 19:52:38 +00:00
static const InetAddress NULL_INET_ADDR ;
2017-06-05 19:15:28 +00:00
// Fake TLS hello for TCP tunnel outgoing connections (TUNNELED mode)
static const char ZT_TCP_TUNNEL_HELLO [ 9 ] = { 0x17 , 0x03 , 0x03 , 0x00 , 0x04 , ( char ) ZEROTIER_ONE_VERSION_MAJOR , ( char ) ZEROTIER_ONE_VERSION_MINOR , ( char ) ( ( ZEROTIER_ONE_VERSION_REVISION > > 8 ) & 0xff ) , ( char ) ( ZEROTIER_ONE_VERSION_REVISION & 0xff ) } ;
2015-12-01 00:44:32 +00:00
2015-10-01 19:37:18 +00:00
static std : : string _trimString ( const std : : string & s )
{
unsigned long end = ( unsigned long ) s . length ( ) ;
while ( end ) {
char c = s [ end - 1 ] ;
if ( ( c = = ' ' ) | | ( c = = ' \r ' ) | | ( c = = ' \n ' ) | | ( ! c ) | | ( c = = ' \t ' ) )
- - end ;
else break ;
}
unsigned long start = 0 ;
while ( start < end ) {
char c = s [ start ] ;
if ( ( c = = ' ' ) | | ( c = = ' \r ' ) | | ( c = = ' \n ' ) | | ( ! c ) | | ( c = = ' \t ' ) )
+ + start ;
else break ;
}
return s . substr ( start , end - start ) ;
}
2021-11-29 22:11:29 +00:00
static void _networkToJson ( nlohmann : : json & nj , NetworkState & ns )
2017-03-07 21:53:11 +00:00
{
char tmp [ 256 ] ;
const char * nstatus = " " , * ntype = " " ;
2021-11-29 22:11:29 +00:00
switch ( ns . config ( ) . status ) {
2017-03-07 21:53:11 +00:00
case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION : nstatus = " REQUESTING_CONFIGURATION " ; break ;
case ZT_NETWORK_STATUS_OK : nstatus = " OK " ; break ;
case ZT_NETWORK_STATUS_ACCESS_DENIED : nstatus = " ACCESS_DENIED " ; break ;
case ZT_NETWORK_STATUS_NOT_FOUND : nstatus = " NOT_FOUND " ; break ;
case ZT_NETWORK_STATUS_PORT_ERROR : nstatus = " PORT_ERROR " ; break ;
case ZT_NETWORK_STATUS_CLIENT_TOO_OLD : nstatus = " CLIENT_TOO_OLD " ; break ;
2021-05-25 16:58:33 +00:00
case ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED : nstatus = " AUTHENTICATION_REQUIRED " ; break ;
2017-03-07 21:53:11 +00:00
}
2021-11-29 22:11:29 +00:00
switch ( ns . config ( ) . type ) {
2017-03-07 21:53:11 +00:00
case ZT_NETWORK_TYPE_PRIVATE : ntype = " PRIVATE " ; break ;
case ZT_NETWORK_TYPE_PUBLIC : ntype = " PUBLIC " ; break ;
}
2015-04-11 02:08:49 +00:00
2021-11-29 22:11:29 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.16llx " , ns . config ( ) . nwid ) ;
2017-03-07 21:53:11 +00:00
nj [ " id " ] = tmp ;
nj [ " nwid " ] = tmp ;
2021-11-29 22:11:29 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( unsigned int ) ( ( ns . config ( ) . mac > > 40 ) & 0xff ) , ( unsigned int ) ( ( ns . config ( ) . mac > > 32 ) & 0xff ) , ( unsigned int ) ( ( ns . config ( ) . mac > > 24 ) & 0xff ) , ( unsigned int ) ( ( ns . config ( ) . mac > > 16 ) & 0xff ) , ( unsigned int ) ( ( ns . config ( ) . mac > > 8 ) & 0xff ) , ( unsigned int ) ( ns . config ( ) . mac & 0xff ) ) ;
2017-03-07 21:53:11 +00:00
nj [ " mac " ] = tmp ;
2021-11-29 22:11:29 +00:00
nj [ " name " ] = ns . config ( ) . name ;
2017-03-07 21:53:11 +00:00
nj [ " status " ] = nstatus ;
nj [ " type " ] = ntype ;
2021-11-29 22:11:29 +00:00
nj [ " mtu " ] = ns . config ( ) . mtu ;
nj [ " dhcp " ] = ( bool ) ( ns . config ( ) . dhcp ! = 0 ) ;
nj [ " bridge " ] = ( bool ) ( ns . config ( ) . bridge ! = 0 ) ;
nj [ " broadcastEnabled " ] = ( bool ) ( ns . config ( ) . broadcastEnabled ! = 0 ) ;
nj [ " portError " ] = ns . config ( ) . portError ;
nj [ " netconfRevision " ] = ns . config ( ) . netconfRevision ;
nj [ " portDeviceName " ] = ns . tap ( ) - > deviceName ( ) ;
OneService : : NetworkSettings localSettings = ns . settings ( ) ;
2017-03-07 21:53:11 +00:00
nj [ " allowManaged " ] = localSettings . allowManaged ;
nj [ " allowGlobal " ] = localSettings . allowGlobal ;
nj [ " allowDefault " ] = localSettings . allowDefault ;
2020-09-10 22:59:18 +00:00
nj [ " allowDNS " ] = localSettings . allowDNS ;
2017-03-07 21:53:11 +00:00
nlohmann : : json aa = nlohmann : : json : : array ( ) ;
2021-11-29 22:11:29 +00:00
for ( unsigned int i = 0 ; i < ns . config ( ) . assignedAddressCount ; + + i ) {
aa . push_back ( reinterpret_cast < const InetAddress * > ( & ( ns . config ( ) . assignedAddresses [ i ] ) ) - > toString ( tmp ) ) ;
2017-03-07 21:53:11 +00:00
}
nj [ " assignedAddresses " ] = aa ;
nlohmann : : json ra = nlohmann : : json : : array ( ) ;
2021-11-29 22:11:29 +00:00
for ( unsigned int i = 0 ; i < ns . config ( ) . routeCount ; + + i ) {
2017-03-07 21:53:11 +00:00
nlohmann : : json rj ;
2021-11-29 22:11:29 +00:00
rj [ " target " ] = reinterpret_cast < const InetAddress * > ( & ( ns . config ( ) . routes [ i ] . target ) ) - > toString ( tmp ) ;
if ( ns . config ( ) . routes [ i ] . via . ss_family = = ns . config ( ) . routes [ i ] . target . ss_family )
rj [ " via " ] = reinterpret_cast < const InetAddress * > ( & ( ns . config ( ) . routes [ i ] . via ) ) - > toIpString ( tmp ) ;
2017-03-07 21:53:11 +00:00
else rj [ " via " ] = nlohmann : : json ( ) ;
2021-11-29 22:11:29 +00:00
rj [ " flags " ] = ( int ) ns . config ( ) . routes [ i ] . flags ;
rj [ " metric " ] = ( int ) ns . config ( ) . routes [ i ] . metric ;
2017-03-07 21:53:11 +00:00
ra . push_back ( rj ) ;
}
nj [ " routes " ] = ra ;
2019-08-06 20:22:57 +00:00
nlohmann : : json mca = nlohmann : : json : : array ( ) ;
2021-11-29 22:11:29 +00:00
for ( unsigned int i = 0 ; i < ns . config ( ) . multicastSubscriptionCount ; + + i ) {
2019-08-06 20:22:57 +00:00
nlohmann : : json m ;
2021-11-29 22:11:29 +00:00
m [ " mac " ] = MAC ( ns . config ( ) . multicastSubscriptions [ i ] . mac ) . toString ( tmp ) ;
m [ " adi " ] = ns . config ( ) . multicastSubscriptions [ i ] . adi ;
2019-08-06 20:22:57 +00:00
mca . push_back ( m ) ;
}
nj [ " multicastSubscriptions " ] = mca ;
2020-08-04 20:52:57 +00:00
2020-08-12 20:08:47 +00:00
nlohmann : : json m ;
2021-11-29 22:11:29 +00:00
m [ " domain " ] = ns . config ( ) . dns . domain ;
2020-08-12 20:08:47 +00:00
m [ " servers " ] = nlohmann : : json : : array ( ) ;
for ( int j = 0 ; j < ZT_MAX_DNS_SERVERS ; + + j ) {
2021-03-09 20:34:01 +00:00
2021-11-29 22:11:29 +00:00
InetAddress a ( ns . config ( ) . dns . server_addr [ j ] ) ;
2020-08-12 20:08:47 +00:00
if ( a . isV4 ( ) | | a . isV6 ( ) ) {
char buf [ 256 ] ;
m [ " servers " ] . push_back ( a . toIpString ( buf ) ) ;
2020-08-04 20:52:57 +00:00
}
}
2020-08-12 20:08:47 +00:00
nj [ " dns " ] = m ;
2021-11-30 22:22:25 +00:00
if ( ns . config ( ) . ssoEnabled ) {
2021-12-01 21:01:32 +00:00
const char * authURL = ns . getAuthURL ( ) ;
2021-12-16 20:23:09 +00:00
//fprintf(stderr, "Auth URL: %s\n", authURL);
2021-12-01 21:01:32 +00:00
nj [ " authenticationURL " ] = authURL ;
2021-12-03 19:32:29 +00:00
nj [ " authenticationExpiryTime " ] = ( ns . getExpiryTime ( ) * 1000 ) ;
2021-11-30 22:22:25 +00:00
nj [ " ssoEnabled " ] = ns . config ( ) . ssoEnabled ;
}
2017-03-07 21:53:11 +00:00
}
2015-10-22 23:02:01 +00:00
2023-01-11 00:01:07 +00:00
static void _peerToJson ( nlohmann : : json & pj , const ZT_Peer * peer , SharedPtr < Bond > & bond , bool isTunneled )
2017-03-07 21:53:11 +00:00
{
char tmp [ 256 ] ;
const char * prole = " " ;
switch ( peer - > role ) {
case ZT_PEER_ROLE_LEAF : prole = " LEAF " ; break ;
case ZT_PEER_ROLE_MOON : prole = " MOON " ; break ;
case ZT_PEER_ROLE_PLANET : prole = " PLANET " ; break ;
}
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.10llx " , peer - > address ) ;
2017-03-07 21:53:11 +00:00
pj [ " address " ] = tmp ;
pj [ " versionMajor " ] = peer - > versionMajor ;
pj [ " versionMinor " ] = peer - > versionMinor ;
pj [ " versionRev " ] = peer - > versionRev ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %d.%d.%d " , peer - > versionMajor , peer - > versionMinor , peer - > versionRev ) ;
2017-03-07 21:53:11 +00:00
pj [ " version " ] = tmp ;
pj [ " latency " ] = peer - > latency ;
pj [ " role " ] = prole ;
2020-07-28 06:01:12 +00:00
pj [ " isBonded " ] = peer - > isBonded ;
2023-01-11 00:01:07 +00:00
pj [ " tunneled " ] = isTunneled ;
2022-09-20 21:27:34 +00:00
if ( bond & & peer - > isBonded ) {
pj [ " bondingPolicyCode " ] = peer - > bondingPolicy ;
pj [ " bondingPolicyStr " ] = Bond : : getPolicyStrByCode ( peer - > bondingPolicy ) ;
2021-03-09 20:34:01 +00:00
pj [ " numAliveLinks " ] = peer - > numAliveLinks ;
pj [ " numTotalLinks " ] = peer - > numTotalLinks ;
2022-09-20 21:27:34 +00:00
pj [ " failoverInterval " ] = bond - > getFailoverInterval ( ) ;
pj [ " downDelay " ] = bond - > getDownDelay ( ) ;
pj [ " upDelay " ] = bond - > getUpDelay ( ) ;
pj [ " packetsPerLink " ] = bond - > getPacketsPerLink ( ) ;
2021-03-09 20:34:01 +00:00
}
2017-03-07 21:53:11 +00:00
nlohmann : : json pa = nlohmann : : json : : array ( ) ;
for ( unsigned int i = 0 ; i < peer - > pathCount ; + + i ) {
2017-10-05 20:19:25 +00:00
int64_t lastSend = peer - > paths [ i ] . lastSend ;
int64_t lastReceive = peer - > paths [ i ] . lastReceive ;
2017-03-07 21:53:11 +00:00
nlohmann : : json j ;
2017-07-06 23:11:11 +00:00
j [ " address " ] = reinterpret_cast < const InetAddress * > ( & ( peer - > paths [ i ] . address ) ) - > toString ( tmp ) ;
2017-10-05 20:19:25 +00:00
j [ " lastSend " ] = ( lastSend < 0 ) ? 0 : lastSend ;
j [ " lastReceive " ] = ( lastReceive < 0 ) ? 0 : lastReceive ;
2017-03-07 21:53:11 +00:00
j [ " trustedPathId " ] = peer - > paths [ i ] . trustedPathId ;
j [ " active " ] = ( bool ) ( peer - > paths [ i ] . expired = = 0 ) ;
j [ " expired " ] = ( bool ) ( peer - > paths [ i ] . expired ! = 0 ) ;
j [ " preferred " ] = ( bool ) ( peer - > paths [ i ] . preferred ! = 0 ) ;
2022-04-28 22:58:12 +00:00
j [ " localSocket " ] = peer - > paths [ i ] . localSocket ;
2022-09-20 21:27:34 +00:00
if ( bond & & peer - > isBonded ) {
uint64_t now = OSUtils : : now ( ) ;
j [ " ifname " ] = std : : string ( peer - > paths [ i ] . ifname ) ;
j [ " latencyMean " ] = peer - > paths [ i ] . latencyMean ;
j [ " latencyVariance " ] = peer - > paths [ i ] . latencyVariance ;
j [ " packetLossRatio " ] = peer - > paths [ i ] . packetLossRatio ;
j [ " packetErrorRatio " ] = peer - > paths [ i ] . packetErrorRatio ;
j [ " lastInAge " ] = ( now - lastReceive ) ;
j [ " lastOutAge " ] = ( now - lastSend ) ;
j [ " bonded " ] = peer - > paths [ i ] . bonded ;
j [ " eligible " ] = peer - > paths [ i ] . eligible ;
j [ " givenLinkSpeed " ] = peer - > paths [ i ] . linkSpeed ;
2022-10-10 06:07:16 +00:00
j [ " relativeQuality " ] = peer - > paths [ i ] . relativeQuality ;
2022-09-20 21:27:34 +00:00
}
2017-03-07 21:53:11 +00:00
pa . push_back ( j ) ;
}
pj [ " paths " ] = pa ;
}
static void _moonToJson ( nlohmann : : json & mj , const World & world )
{
2017-07-06 23:11:11 +00:00
char tmp [ 4096 ] ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.16llx " , world . id ( ) ) ;
2017-03-07 21:53:11 +00:00
mj [ " id " ] = tmp ;
mj [ " timestamp " ] = world . timestamp ( ) ;
2018-01-27 01:00:37 +00:00
mj [ " signature " ] = Utils : : hex ( world . signature ( ) . data , ZT_C25519_SIGNATURE_LEN , tmp ) ;
mj [ " updatesMustBeSignedBy " ] = Utils : : hex ( world . updatesMustBeSignedBy ( ) . data , ZT_C25519_PUBLIC_KEY_LEN , tmp ) ;
2017-03-07 21:53:11 +00:00
nlohmann : : json ra = nlohmann : : json : : array ( ) ;
for ( std : : vector < World : : Root > : : const_iterator r ( world . roots ( ) . begin ( ) ) ; r ! = world . roots ( ) . end ( ) ; + + r ) {
nlohmann : : json rj ;
2017-07-06 23:11:11 +00:00
rj [ " identity " ] = r - > identity . toString ( false , tmp ) ;
2017-03-07 21:53:11 +00:00
nlohmann : : json eps = nlohmann : : json : : array ( ) ;
for ( std : : vector < InetAddress > : : const_iterator a ( r - > stableEndpoints . begin ( ) ) ; a ! = r - > stableEndpoints . end ( ) ; + + a )
2017-07-06 23:11:11 +00:00
eps . push_back ( a - > toString ( tmp ) ) ;
2017-03-07 21:53:11 +00:00
rj [ " stableEndpoints " ] = eps ;
ra . push_back ( rj ) ;
}
mj [ " roots " ] = ra ;
mj [ " waiting " ] = false ;
}
2015-04-15 21:42:26 +00:00
class OneServiceImpl ;
2015-04-11 02:08:49 +00:00
2017-03-28 00:03:17 +00:00
static int SnodeVirtualNetworkConfigFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t nwid , void * * nuptr , enum ZT_VirtualNetworkConfigOperation op , const ZT_VirtualNetworkConfig * nwconf ) ;
static void SnodeEventCallback ( ZT_Node * node , void * uptr , void * tptr , enum ZT_Event event , const void * metaData ) ;
2017-07-01 00:32:07 +00:00
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 ) ;
2017-07-06 18:45:22 +00:00
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 ) ;
2017-03-28 00:03:17 +00:00
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 ) ;
2017-07-06 18:45:22 +00:00
static int SnodePathCheckFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , int64_t localSocket , const struct sockaddr_storage * remoteAddr ) ;
2017-03-28 00:03:17 +00:00
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 ) ;
2015-04-15 00:57:51 +00:00
2015-04-11 02:08:49 +00:00
static int ShttpOnMessageBegin ( http_parser * parser ) ;
static int ShttpOnUrl ( http_parser * parser , const char * ptr , size_t length ) ;
2016-06-08 19:49:07 +00:00
# if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
2015-04-11 02:08:49 +00:00
static int ShttpOnStatus ( http_parser * parser , const char * ptr , size_t length ) ;
2016-06-08 19:49:07 +00:00
# else
static int ShttpOnStatus ( http_parser * parser ) ;
# endif
2015-04-11 02:08:49 +00:00
static int ShttpOnHeaderField ( http_parser * parser , const char * ptr , size_t length ) ;
static int ShttpOnValue ( http_parser * parser , const char * ptr , size_t length ) ;
static int ShttpOnHeadersComplete ( http_parser * parser ) ;
static int ShttpOnBody ( http_parser * parser , const char * ptr , size_t length ) ;
static int ShttpOnMessageComplete ( http_parser * parser ) ;
2016-06-08 22:09:09 +00:00
# if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1)
2015-04-16 21:13:44 +00:00
static const struct http_parser_settings HTTP_PARSER_SETTINGS = {
2015-04-11 02:08:49 +00:00
ShttpOnMessageBegin ,
ShttpOnUrl ,
ShttpOnStatus ,
ShttpOnHeaderField ,
ShttpOnValue ,
ShttpOnHeadersComplete ,
ShttpOnBody ,
ShttpOnMessageComplete
} ;
2016-06-08 22:09:09 +00:00
# else
static const struct http_parser_settings HTTP_PARSER_SETTINGS = {
ShttpOnMessageBegin ,
ShttpOnUrl ,
ShttpOnHeaderField ,
ShttpOnValue ,
ShttpOnHeadersComplete ,
ShttpOnBody ,
ShttpOnMessageComplete
} ;
# endif
2015-04-11 00:07:06 +00:00
2017-06-05 19:15:28 +00:00
/**
* A TCP connection and related state and buffers
*/
2015-04-28 19:43:10 +00:00
struct TcpConnection
2015-04-11 02:08:49 +00:00
{
2015-04-28 19:43:10 +00:00
enum {
2017-06-05 19:15:28 +00:00
TCP_UNCATEGORIZED_INCOMING , // uncategorized incoming connection
2015-04-28 19:43:10 +00:00
TCP_HTTP_INCOMING ,
2017-06-05 19:15:28 +00:00
TCP_HTTP_OUTGOING ,
2017-07-06 18:45:22 +00:00
TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection
2015-04-28 19:43:10 +00:00
} type ;
2015-04-15 21:42:26 +00:00
OneServiceImpl * parent ;
2015-04-11 02:08:49 +00:00
PhySocket * sock ;
2017-06-06 23:11:19 +00:00
InetAddress remoteAddr ;
2017-07-06 23:29:11 +00:00
uint64_t lastReceive ;
2017-06-05 19:15:28 +00:00
// Used for inbound HTTP connections
2015-04-11 02:08:49 +00:00
http_parser parser ;
unsigned long messageSize ;
std : : string currentHeaderField ;
std : : string currentHeaderValue ;
std : : string url ;
std : : string status ;
std : : map < std : : string , std : : string > headers ;
2015-04-28 19:43:10 +00:00
2017-06-05 19:15:28 +00:00
std : : string readq ;
std : : string writeq ;
Mutex writeq_m ;
2015-04-11 02:08:49 +00:00
} ;
2015-04-11 00:07:06 +00:00
2018-11-13 20:07:58 +00:00
struct OneServiceIncomingPacket
{
uint64_t now ;
int64_t sock ;
struct sockaddr_storage from ;
unsigned int size ;
uint8_t data [ ZT_MAX_MTU ] ;
} ;
2015-04-15 21:42:26 +00:00
class OneServiceImpl : public OneService
2015-04-10 01:14:27 +00:00
{
public :
2016-04-05 18:59:46 +00:00
// begin member variables --------------------------------------------------
const std : : string _homePath ;
2017-03-07 21:53:11 +00:00
std : : string _authToken ;
2017-04-19 00:37:44 +00:00
std : : string _controllerDbPath ;
2017-06-02 03:32:43 +00:00
const std : : string _networksPath ;
const std : : string _moonsPath ;
2016-08-17 17:42:32 +00:00
EmbeddedNetworkController * _controller ;
2016-04-05 18:59:46 +00:00
Phy < OneServiceImpl * > _phy ;
Node * _node ;
2017-01-12 00:34:33 +00:00
SoftwareUpdater * _updater ;
2017-01-12 21:18:11 +00:00
bool _updateAutoApply ;
2023-04-28 18:03:28 +00:00
httplib : : Server _controlPlane ;
std : : thread _serverThread ;
bool _allowTcpFallbackRelay ;
2023-01-11 00:01:07 +00:00
bool _forceTcpRelay ;
2019-07-09 17:31:03 +00:00
bool _allowSecondaryPort ;
2020-05-12 08:35:48 +00:00
2016-12-13 00:25:41 +00:00
unsigned int _primaryPort ;
2018-09-10 20:06:05 +00:00
unsigned int _secondaryPort ;
unsigned int _tertiaryPort ;
2017-06-02 03:32:43 +00:00
volatile unsigned int _udpPortPickerCounter ;
2016-04-05 18:59:46 +00:00
2017-06-05 19:15:28 +00:00
// Local configuration and memo-ized information from it
2016-11-22 18:54:58 +00:00
json _localConfig ;
Hashtable < uint64_t , std : : vector < InetAddress > > _v4Hints ;
Hashtable < uint64_t , std : : vector < InetAddress > > _v6Hints ;
Hashtable < uint64_t , std : : vector < InetAddress > > _v4Blacklists ;
Hashtable < uint64_t , std : : vector < InetAddress > > _v6Blacklists ;
std : : vector < InetAddress > _globalV4Blacklist ;
std : : vector < InetAddress > _globalV6Blacklist ;
2016-12-13 00:25:41 +00:00
std : : vector < InetAddress > _allowManagementFrom ;
2016-12-12 22:43:09 +00:00
std : : vector < std : : string > _interfacePrefixBlacklist ;
2016-11-22 18:54:58 +00:00
Mutex _localConfig_m ;
2016-04-05 18:59:46 +00:00
2018-09-11 23:55:46 +00:00
std : : vector < InetAddress > explicitBind ;
2016-04-05 18:59:46 +00:00
/*
2016-06-14 17:09:26 +00:00
* To attempt to handle NAT / gateway craziness we use three local UDP ports :
2016-04-05 18:59:46 +00:00
*
* [ 0 ] is the normal / default port , usually 9993
2018-09-10 20:06:05 +00:00
* [ 1 ] is a port derived from our ZeroTier address
2016-04-05 18:59:46 +00:00
* [ 2 ] is a port computed from the normal / default for use with uPnP / NAT - PMP mappings
*
* [ 2 ] exists because on some gateways trying to do regular NAT - t interferes
* destructively with uPnP port mapping behavior in very weird buggy ways .
* It ' s only used if uPnP / NAT - PMP is enabled in this build .
*/
2016-04-05 22:44:08 +00:00
unsigned int _ports [ 3 ] ;
2017-06-06 23:11:19 +00:00
Binder _binder ;
2016-04-05 18:59:46 +00:00
// Time we last received a packet from a global address
uint64_t _lastDirectReceiveFromGlobal ;
# ifdef ZT_TCP_FALLBACK_RELAY
2022-04-28 18:05:54 +00:00
InetAddress _fallbackRelayAddress ;
2016-04-05 18:59:46 +00:00
uint64_t _lastSendToGlobalV4 ;
# endif
// Last potential sleep/wake event
uint64_t _lastRestart ;
// Deadline for the next background task service function
2017-10-02 22:52:57 +00:00
volatile int64_t _nextBackgroundTaskDeadline ;
2016-04-05 18:59:46 +00:00
2021-11-29 22:11:29 +00:00
2021-11-18 20:39:55 +00:00
2016-06-14 17:09:26 +00:00
std : : map < uint64_t , NetworkState > _nets ;
Mutex _nets_m ;
2016-04-05 18:59:46 +00:00
// Active TCP/IP connections
2017-06-05 19:15:28 +00:00
std : : vector < TcpConnection * > _tcpConnections ;
Mutex _tcpConnections_m ;
2016-04-05 18:59:46 +00:00
TcpConnection * _tcpFallbackTunnel ;
// Termination status information
ReasonForTermination _termReason ;
std : : string _fatalErrorMessage ;
Mutex _termReason_m ;
// uPnP/NAT-PMP port mapper if enabled
2017-01-19 23:57:50 +00:00
bool _portMappingEnabled ; // local.conf settings
2016-04-05 18:59:46 +00:00
# ifdef ZT_USE_MINIUPNPC
PortMapper * _portMapper ;
# endif
2018-08-09 21:32:26 +00:00
// HashiCorp Vault Settings
# if ZT_VAULT_SUPPORT
bool _vaultEnabled ;
std : : string _vaultURL ;
std : : string _vaultToken ;
std : : string _vaultPath ; // defaults to cubbyhole/zerotier/identity.secret for per-access key storage
# endif
2016-04-05 18:59:46 +00:00
// Set to false to force service to stop
volatile bool _run ;
Mutex _run_m ;
2020-05-11 22:03:56 +00:00
RedisConfig * _rc ;
2021-06-04 23:29:03 +00:00
std : : string _ssoRedirectURL ;
2020-05-11 22:03:56 +00:00
2016-04-05 18:59:46 +00:00
// end member variables ----------------------------------------------------
2015-10-13 15:49:36 +00:00
OneServiceImpl ( const char * hp , unsigned int port ) :
2015-10-22 23:02:01 +00:00
_homePath ( ( hp ) ? hp : " . " )
2017-06-02 03:32:43 +00:00
, _controllerDbPath ( _homePath + ZT_PATH_SEPARATOR_S " controller.d " )
, _networksPath ( _homePath + ZT_PATH_SEPARATOR_S " networks.d " )
, _moonsPath ( _homePath + ZT_PATH_SEPARATOR_S " moons.d " )
2016-08-17 17:42:32 +00:00
, _controller ( ( EmbeddedNetworkController * ) 0 )
2015-10-22 23:02:01 +00:00
, _phy ( this , false , true )
, _node ( ( Node * ) 0 )
2017-01-12 00:34:33 +00:00
, _updater ( ( SoftwareUpdater * ) 0 )
2017-01-12 21:18:11 +00:00
, _updateAutoApply ( false )
2023-04-28 18:03:28 +00:00
, _controlPlane ( )
, _serverThread ( )
2023-01-11 00:01:07 +00:00
, _forceTcpRelay ( false )
2016-12-13 00:25:41 +00:00
, _primaryPort ( port )
2017-06-02 03:32:43 +00:00
, _udpPortPickerCounter ( 0 )
2015-10-22 23:02:01 +00:00
, _lastDirectReceiveFromGlobal ( 0 )
2016-03-03 21:52:27 +00:00
# ifdef ZT_TCP_FALLBACK_RELAY
2022-04-28 18:05:54 +00:00
, _fallbackRelayAddress ( ZT_TCP_FALLBACK_RELAY )
2016-03-03 21:52:27 +00:00
, _lastSendToGlobalV4 ( 0 )
# endif
2015-10-22 23:02:01 +00:00
, _lastRestart ( 0 )
, _nextBackgroundTaskDeadline ( 0 )
, _tcpFallbackTunnel ( ( TcpConnection * ) 0 )
, _termReason ( ONE_STILL_RUNNING )
2017-01-19 23:57:50 +00:00
, _portMappingEnabled ( true )
2015-07-28 21:32:02 +00:00
# ifdef ZT_USE_MINIUPNPC
2015-11-30 21:10:22 +00:00
, _portMapper ( ( PortMapper * ) 0 )
2018-08-09 21:32:26 +00:00
# endif
# ifdef ZT_VAULT_SUPPORT
, _vaultEnabled ( false )
, _vaultURL ( )
, _vaultToken ( )
, _vaultPath ( " cubbyhole/zerotier " )
2015-10-22 23:02:01 +00:00
# endif
, _run ( true )
2020-05-11 22:03:56 +00:00
, _rc ( NULL )
2021-06-04 23:29:03 +00:00
, _ssoRedirectURL ( )
2015-04-10 01:14:27 +00:00
{
2016-04-05 22:44:08 +00:00
_ports [ 0 ] = 0 ;
_ports [ 1 ] = 0 ;
_ports [ 2 ] = 0 ;
2018-11-12 06:35:15 +00:00
2023-04-21 19:12:43 +00:00
prometheus : : simpleapi : : saver . set_registry ( prometheus : : simpleapi : : registry_ptr ) ;
prometheus : : simpleapi : : saver . set_delay ( std : : chrono : : seconds ( 5 ) ) ;
prometheus : : simpleapi : : saver . set_out_file ( _homePath + ZT_PATH_SEPARATOR + " metrics.prom " ) ;
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
curl_global_init ( CURL_GLOBAL_DEFAULT ) ;
# endif
2015-04-10 01:14:27 +00:00
}
2015-04-15 21:42:26 +00:00
virtual ~ OneServiceImpl ( )
2015-04-10 01:14:27 +00:00
{
2022-12-19 21:26:29 +00:00
# ifdef __WINDOWS__
WinFWHelper : : removeICMPRules ( ) ;
# endif
2017-06-06 23:11:19 +00:00
_binder . closeAll ( _phy ) ;
2018-11-13 20:07:58 +00:00
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
curl_global_cleanup ( ) ;
# endif
2023-04-28 18:03:28 +00:00
_controlPlane . stop ( ) ;
_serverThread . join ( ) ;
2022-12-19 21:26:29 +00:00
2015-09-23 21:38:16 +00:00
# ifdef ZT_USE_MINIUPNPC
2015-11-30 21:10:22 +00:00
delete _portMapper ;
2015-10-06 22:56:18 +00:00
# endif
delete _controller ;
2020-05-11 22:03:56 +00:00
delete _rc ;
2015-04-10 01:14:27 +00:00
}
2015-04-10 18:40:45 +00:00
virtual ReasonForTermination run ( )
{
try {
2015-04-16 02:14:12 +00:00
{
2017-03-07 21:53:11 +00:00
const std : : string authTokenPath ( _homePath + ZT_PATH_SEPARATOR_S " authtoken.secret " ) ;
if ( ! OSUtils : : readFile ( authTokenPath . c_str ( ) , _authToken ) ) {
2015-04-16 02:14:12 +00:00
unsigned char foo [ 24 ] ;
Utils : : getSecureRandom ( foo , sizeof ( foo ) ) ;
2017-03-07 21:53:11 +00:00
_authToken = " " ;
2015-04-16 02:14:12 +00:00
for ( unsigned int i = 0 ; i < sizeof ( foo ) ; + + i )
2017-03-07 21:53:11 +00:00
_authToken . push_back ( " abcdefghijklmnopqrstuvwxyz0123456789 " [ ( unsigned long ) foo [ i ] % 36 ] ) ;
if ( ! OSUtils : : writeFile ( authTokenPath . c_str ( ) , _authToken ) ) {
2015-04-16 02:14:12 +00:00
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = " authtoken.secret could not be written " ;
return _termReason ;
2016-04-05 22:44:08 +00:00
} else {
OSUtils : : lockDownFile ( authTokenPath . c_str ( ) , false ) ;
}
2015-04-16 02:14:12 +00:00
}
2017-03-07 21:53:11 +00:00
_authToken = _trimString ( _authToken ) ;
2016-03-03 21:52:27 +00:00
}
2016-11-22 18:54:58 +00:00
{
struct ZT_Node_Callbacks cb ;
cb . version = 0 ;
2017-06-02 03:32:43 +00:00
cb . stateGetFunction = SnodeStateGetFunction ;
cb . statePutFunction = SnodeStatePutFunction ;
2016-11-22 18:54:58 +00:00
cb . wirePacketSendFunction = SnodeWirePacketSendFunction ;
cb . virtualNetworkFrameFunction = SnodeVirtualNetworkFrameFunction ;
cb . virtualNetworkConfigFunction = SnodeVirtualNetworkConfigFunction ;
cb . eventCallback = SnodeEventCallback ;
cb . pathCheckFunction = SnodePathCheckFunction ;
cb . pathLookupFunction = SnodePathLookupFunction ;
2017-03-28 00:03:17 +00:00
_node = new Node ( this , ( void * ) 0 , & cb , OSUtils : : now ( ) ) ;
2015-11-30 21:10:22 +00:00
}
2016-04-05 22:44:08 +00:00
2022-12-19 21:26:29 +00:00
2018-09-11 23:55:46 +00:00
// local.conf
readLocalSettings ( ) ;
2016-11-22 18:54:58 +00:00
applyLocalConfig ( ) ;
2015-10-22 23:02:01 +00:00
2021-03-09 01:25:41 +00:00
// Save original port number to show it if bind error
const int _configuredPort = _primaryPort ;
2017-06-06 23:11:19 +00:00
// Make sure we can use the primary port, and hunt for one if configured to do so
2016-12-13 00:25:41 +00:00
const int portTrials = ( _primaryPort = = 0 ) ? 256 : 1 ; // if port is 0, pick random
for ( int k = 0 ; k < portTrials ; + + k ) {
if ( _primaryPort = = 0 ) {
unsigned int randp = 0 ;
Utils : : getSecureRandom ( & randp , sizeof ( randp ) ) ;
_primaryPort = 20000 + ( randp % 45500 ) ;
}
if ( _trialBind ( _primaryPort ) ) {
2017-06-06 23:11:19 +00:00
_ports [ 0 ] = _primaryPort ;
2016-12-13 00:25:41 +00:00
} else {
_primaryPort = 0 ;
}
}
if ( _ports [ 0 ] = = 0 ) {
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
2021-03-09 01:25:41 +00:00
_fatalErrorMessage = std : : string ( " cannot bind to local control interface port " ) + std : : to_string ( _configuredPort ) ;
2016-12-13 00:25:41 +00:00
return _termReason ;
}
2017-06-02 03:32:43 +00:00
// Save primary port to a file so CLIs and GUIs can learn it easily
2016-12-13 00:25:41 +00:00
char portstr [ 64 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( portstr , sizeof ( portstr ) , " %u " , _ports [ 0 ] ) ;
2017-01-27 21:27:52 +00:00
OSUtils : : writeFile ( ( _homePath + ZT_PATH_SEPARATOR_S " zerotier-one.port " ) . c_str ( ) , std : : string ( portstr ) ) ;
2016-12-13 00:25:41 +00:00
2021-05-27 22:41:11 +00:00
// Attempt to bind to a secondary port.
2016-12-13 00:25:41 +00:00
// This exists because there are buggy NATs out there that fail if more
// than one device behind the same NAT tries to use the same internal
2017-06-06 23:11:19 +00:00
// private address port number. Buggy NATs are a running theme.
2021-05-27 22:41:11 +00:00
//
// This used to pick the secondary port based on the node ID until we
// discovered another problem: buggy routers and malicious traffic
// "detection". A lot of routers have such things built in these days
// and mis-detect ZeroTier traffic as malicious and block it resulting
// in a node that appears to be in a coma. Secondary ports are now
// randomized on startup.
2019-07-09 17:31:03 +00:00
if ( _allowSecondaryPort ) {
2019-11-11 20:03:49 +00:00
if ( _secondaryPort ) {
_ports [ 1 ] = _secondaryPort ;
} else {
2021-08-31 20:47:00 +00:00
_ports [ 1 ] = _getRandomPort ( ) ;
2016-12-13 00:25:41 +00:00
}
}
# ifdef ZT_USE_MINIUPNPC
2017-01-19 23:57:50 +00:00
if ( _portMappingEnabled ) {
// If we're running uPnP/NAT-PMP, bind a *third* port for that. We can't
// use the other two ports for that because some NATs do really funky
// stuff with ports that are explicitly mapped that breaks things.
2022-04-13 20:53:42 +00:00
if ( _tertiaryPort ) {
_ports [ 2 ] = _tertiaryPort ;
} else {
_ports [ 2 ] = _getRandomPort ( ) ;
}
if ( _ports [ 2 ] ) {
char uniqueName [ 64 ] ;
OSUtils : : ztsnprintf ( uniqueName , sizeof ( uniqueName ) , " ZeroTier/%.10llx@%u " , _node - > address ( ) , _ports [ 2 ] ) ;
_portMapper = new PortMapper ( _ports [ 2 ] , uniqueName ) ;
2015-10-22 23:02:01 +00:00
}
}
# endif
2020-05-12 08:35:48 +00:00
2017-07-06 17:25:36 +00:00
// Delete legacy iddb.d if present (cleanup)
OSUtils : : rmDashRf ( ( _homePath + ZT_PATH_SEPARATOR_S " iddb.d " ) . c_str ( ) ) ;
2015-05-17 22:51:07 +00:00
2017-06-02 03:32:43 +00:00
// Network controller is now enabled by default for desktop and server
2020-05-11 22:03:56 +00:00
_controller = new EmbeddedNetworkController ( _node , _homePath . c_str ( ) , _controllerDbPath . c_str ( ) , _ports [ 0 ] , _rc ) ;
2021-06-04 23:29:03 +00:00
if ( ! _ssoRedirectURL . empty ( ) ) {
_controller - > setSSORedirectURL ( _ssoRedirectURL ) ;
}
2015-10-06 22:56:18 +00:00
_node - > setNetconfMaster ( ( void * ) _controller ) ;
2015-04-14 01:12:45 +00:00
2023-04-28 18:03:28 +00:00
startHTTPControlPlane ( ) ;
2017-06-06 23:11:19 +00:00
// Join existing networks in networks.d
{
2017-01-27 21:27:52 +00:00
std : : vector < std : : string > networksDotD ( OSUtils : : listDirectory ( ( _homePath + ZT_PATH_SEPARATOR_S " networks.d " ) . c_str ( ) ) ) ;
2015-04-14 22:32:05 +00:00
for ( std : : vector < std : : string > : : iterator f ( networksDotD . begin ( ) ) ; f ! = networksDotD . end ( ) ; + + f ) {
std : : size_t dot = f - > find_last_of ( ' . ' ) ;
if ( ( dot = = 16 ) & & ( f - > substr ( 16 ) = = " .conf " ) )
2017-03-28 00:03:17 +00:00
_node - > join ( Utils : : hexStrToU64 ( f - > substr ( 0 , dot ) . c_str ( ) ) , ( void * ) 0 , ( void * ) 0 ) ;
2015-04-14 22:32:05 +00:00
}
}
2017-06-06 23:11:19 +00:00
// Orbit existing moons in moons.d
{
2017-01-27 23:27:26 +00:00
std : : vector < std : : string > moonsDotD ( OSUtils : : listDirectory ( ( _homePath + ZT_PATH_SEPARATOR_S " moons.d " ) . c_str ( ) ) ) ;
for ( std : : vector < std : : string > : : iterator f ( moonsDotD . begin ( ) ) ; f ! = moonsDotD . end ( ) ; + + f ) {
std : : size_t dot = f - > find_last_of ( ' . ' ) ;
if ( ( dot = = 16 ) & & ( f - > substr ( 16 ) = = " .moon " ) )
2017-03-28 00:03:17 +00:00
_node - > orbit ( ( void * ) 0 , Utils : : hexStrToU64 ( f - > substr ( 0 , dot ) . c_str ( ) ) , 0 ) ;
2017-01-27 23:27:26 +00:00
}
}
2015-11-05 20:41:14 +00:00
2017-06-02 03:32:43 +00:00
// Main I/O loop
2015-04-10 18:40:45 +00:00
_nextBackgroundTaskDeadline = 0 ;
2017-10-02 22:52:57 +00:00
int64_t clockShouldBe = OSUtils : : now ( ) ;
2015-05-22 21:52:23 +00:00
_lastRestart = clockShouldBe ;
2017-10-02 22:52:57 +00:00
int64_t lastTapMulticastGroupCheck = 0 ;
int64_t lastBindRefresh = 0 ;
int64_t lastUpdateCheck = clockShouldBe ;
2017-10-25 23:08:14 +00:00
int64_t lastCleanedPeersDb = 0 ;
2017-10-02 22:52:57 +00:00
int64_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
2018-09-11 23:55:46 +00:00
int64_t lastLocalConfFileCheck = OSUtils : : now ( ) ;
2021-08-31 20:47:00 +00:00
int64_t lastOnline = lastLocalConfFileCheck ;
2015-04-10 18:40:45 +00:00
for ( ; ; ) {
_run_m . lock ( ) ;
if ( ! _run ) {
_run_m . unlock ( ) ;
_termReason_m . lock ( ) ;
_termReason = ONE_NORMAL_TERMINATION ;
_termReason_m . unlock ( ) ;
break ;
2016-04-05 22:44:08 +00:00
} else {
_run_m . unlock ( ) ;
}
2015-04-10 18:40:45 +00:00
2017-10-02 22:52:57 +00:00
const int64_t now = OSUtils : : now ( ) ;
2016-04-05 22:44:08 +00:00
// Attempt to detect sleep/wake events by detecting delay overruns
bool restarted = false ;
if ( ( now > clockShouldBe ) & & ( ( now - clockShouldBe ) > 10000 ) ) {
_lastRestart = now ;
restarted = true ;
}
2017-01-12 00:34:33 +00:00
// Check for updates (if enabled)
if ( ( _updater ) & & ( ( now - lastUpdateCheck ) > 10000 ) ) {
lastUpdateCheck = now ;
2017-01-12 21:54:08 +00:00
if ( _updater - > check ( now ) & & _updateAutoApply )
_updater - > apply ( ) ;
2017-01-12 00:34:33 +00:00
}
2018-09-11 23:55:46 +00:00
// Reload local.conf if anything changed recently
if ( ( now - lastLocalConfFileCheck ) > = ZT_LOCAL_CONF_FILE_CHECK_INTERVAL ) {
lastLocalConfFileCheck = now ;
struct stat result ;
if ( stat ( ( _homePath + ZT_PATH_SEPARATOR_S " local.conf " ) . c_str ( ) , & result ) = = 0 ) {
int64_t mod_time = result . st_mtime * 1000 ;
if ( ( now - mod_time ) < = ZT_LOCAL_CONF_FILE_CHECK_INTERVAL ) {
readLocalSettings ( ) ;
applyLocalConfig ( ) ;
}
}
}
2021-08-31 20:47:00 +00:00
// If secondary port is not configured to a constant value and we've been offline for a while,
// bind a new secondary port. This is a workaround for a "coma" issue caused by buggy NATs that stop
// working on one port after a while.
if ( _node - > online ( ) ) {
lastOnline = now ;
} else if ( ( _secondaryPort = = 0 ) & & ( ( now - lastOnline ) > ZT_PATH_HEARTBEAT_PERIOD ) ) {
_secondaryPort = _getRandomPort ( ) ;
lastBindRefresh = 0 ;
}
2016-06-17 20:14:48 +00:00
// Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default)
2020-05-12 08:35:48 +00:00
if ( ( ( now - lastBindRefresh ) > = ( _node - > bondController ( ) - > inUse ( ) ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD ) ) | | ( restarted ) ) {
2016-04-05 22:44:08 +00:00
lastBindRefresh = now ;
2017-06-06 23:11:19 +00:00
unsigned int p [ 3 ] ;
unsigned int pc = 0 ;
2016-04-05 22:44:08 +00:00
for ( int i = 0 ; i < 3 ; + + i ) {
2017-06-06 23:11:19 +00:00
if ( _ports [ i ] )
p [ pc + + ] = _ports [ i ] ;
2016-04-05 22:44:08 +00:00
}
2023-01-11 00:01:07 +00:00
if ( ! _forceTcpRelay ) {
// Only bother binding UDP ports if we aren't forcing TCP-relay mode
_binder . refresh ( _phy , p , pc , explicitBind , * this ) ;
}
2016-06-17 20:14:48 +00:00
{
Mutex : : Lock _l ( _nets_m ) ;
for ( std : : map < uint64_t , NetworkState > : : iterator n ( _nets . begin ( ) ) ; n ! = _nets . end ( ) ; + + n ) {
2021-11-18 20:39:55 +00:00
if ( n - > second . tap ( ) )
2020-07-31 18:42:03 +00:00
syncManagedStuff ( n - > second , false , true , false ) ;
2016-06-17 20:14:48 +00:00
}
}
2016-04-05 22:44:08 +00:00
}
2015-05-22 21:52:23 +00:00
2017-06-06 23:11:19 +00:00
// Run background task processor in core if it's time to do so
2017-10-02 22:52:57 +00:00
int64_t dl = _nextBackgroundTaskDeadline ;
2015-04-10 18:40:45 +00:00
if ( dl < = now ) {
2017-03-28 00:03:17 +00:00
_node - > processBackgroundTasks ( ( void * ) 0 , now , & _nextBackgroundTaskDeadline ) ;
2015-04-10 18:40:45 +00:00
dl = _nextBackgroundTaskDeadline ;
2015-04-15 20:09:20 +00:00
}
2017-06-06 23:11:19 +00:00
// Close TCP fallback tunnel if we have direct UDP
2023-01-11 00:01:07 +00:00
if ( ! _forceTcpRelay & & ( _tcpFallbackTunnel ) & & ( ( now - _lastDirectReceiveFromGlobal ) < ( ZT_TCP_FALLBACK_AFTER / 2 ) ) ) {
2015-05-22 01:33:52 +00:00
_phy . close ( _tcpFallbackTunnel - > sock ) ;
2023-01-11 00:01:07 +00:00
}
2015-05-22 01:33:52 +00:00
2017-06-06 23:11:19 +00:00
// Sync multicast group memberships
2015-04-15 20:09:20 +00:00
if ( ( now - lastTapMulticastGroupCheck ) > = ZT_TAP_CHECK_MULTICAST_INTERVAL ) {
lastTapMulticastGroupCheck = now ;
2018-01-11 22:29:57 +00:00
std : : vector < std : : pair < uint64_t , std : : pair < std : : vector < MulticastGroup > , std : : vector < MulticastGroup > > > > mgChanges ;
{
Mutex : : Lock _l ( _nets_m ) ;
mgChanges . reserve ( _nets . size ( ) + 1 ) ;
for ( std : : map < uint64_t , NetworkState > : : const_iterator n ( _nets . begin ( ) ) ; n ! = _nets . end ( ) ; + + n ) {
2021-11-18 20:39:55 +00:00
if ( n - > second . tap ( ) ) {
2018-01-11 22:29:57 +00:00
mgChanges . push_back ( std : : pair < uint64_t , std : : pair < std : : vector < MulticastGroup > , std : : vector < MulticastGroup > > > ( n - > first , std : : pair < std : : vector < MulticastGroup > , std : : vector < MulticastGroup > > ( ) ) ) ;
2021-11-18 20:39:55 +00:00
n - > second . tap ( ) - > scanMulticastGroups ( mgChanges . back ( ) . second . first , mgChanges . back ( ) . second . second ) ;
2018-01-11 22:29:57 +00:00
}
2016-06-14 17:09:26 +00:00
}
2015-04-15 20:09:20 +00:00
}
2018-01-11 22:29:57 +00:00
for ( std : : vector < std : : pair < uint64_t , std : : pair < std : : vector < MulticastGroup > , std : : vector < MulticastGroup > > > > : : iterator c ( mgChanges . begin ( ) ) ; c ! = mgChanges . end ( ) ; + + c ) {
for ( std : : vector < MulticastGroup > : : iterator m ( c - > second . first . begin ( ) ) ; m ! = c - > second . first . end ( ) ; + + m )
_node - > multicastSubscribe ( ( void * ) 0 , c - > first , m - > mac ( ) . toInt ( ) , m - > adi ( ) ) ;
for ( std : : vector < MulticastGroup > : : iterator m ( c - > second . second . begin ( ) ) ; m ! = c - > second . second . end ( ) ; + + m )
_node - > multicastUnsubscribe ( c - > first , m - > mac ( ) . toInt ( ) , m - > adi ( ) ) ;
}
2015-04-10 18:40:45 +00:00
}
2017-06-06 23:11:19 +00:00
// Sync information about physical network interfaces
2020-05-12 08:35:48 +00:00
if ( ( now - lastLocalInterfaceAddressCheck ) > = ( _node - > bondController ( ) - > inUse ( ) ? ZT_LOCAL_INTERFACE_CHECK_INTERVAL / 8 : ZT_LOCAL_INTERFACE_CHECK_INTERVAL ) ) {
2015-07-06 23:32:34 +00:00
lastLocalInterfaceAddressCheck = now ;
2016-04-05 22:53:19 +00:00
_node - > clearLocalInterfaceAddresses ( ) ;
2016-01-11 17:11:35 +00:00
2016-04-05 22:53:19 +00:00
# ifdef ZT_USE_MINIUPNPC
if ( _portMapper ) {
std : : vector < InetAddress > mappedAddresses ( _portMapper - > get ( ) ) ;
for ( std : : vector < InetAddress > : : const_iterator ext ( mappedAddresses . begin ( ) ) ; ext ! = mappedAddresses . end ( ) ; + + ext )
_node - > addLocalInterfaceAddress ( reinterpret_cast < const struct sockaddr_storage * > ( & ( * ext ) ) ) ;
2015-07-06 23:32:34 +00:00
}
2016-04-05 22:53:19 +00:00
# endif
2015-07-06 23:32:34 +00:00
2017-06-06 23:11:19 +00:00
std : : vector < InetAddress > boundAddrs ( _binder . allBoundLocalInterfaceAddresses ( ) ) ;
2020-05-12 08:35:48 +00:00
for ( std : : vector < InetAddress > : : const_iterator i ( boundAddrs . begin ( ) ) ; i ! = boundAddrs . end ( ) ; + + i ) {
2016-04-05 22:53:19 +00:00
_node - > addLocalInterfaceAddress ( reinterpret_cast < const struct sockaddr_storage * > ( & ( * i ) ) ) ;
2020-05-12 08:35:48 +00:00
}
2015-07-06 23:32:34 +00:00
}
2017-10-25 23:08:14 +00:00
// Clean peers.d periodically
if ( ( now - lastCleanedPeersDb ) > = 3600000 ) {
lastCleanedPeersDb = now ;
OSUtils : : cleanDirectory ( ( _homePath + ZT_PATH_SEPARATOR_S " peers.d " ) . c_str ( ) , now - 2592000000LL ) ; // delete older than 30 days
}
2020-11-14 01:25:03 +00:00
const unsigned long delay = ( dl > now ) ? ( unsigned long ) ( dl - now ) : 500 ;
clockShouldBe = now + ( int64_t ) delay ;
2015-04-10 18:40:45 +00:00
_phy . poll ( delay ) ;
}
2017-11-04 00:55:16 +00:00
} catch ( std : : exception & e ) {
2015-04-10 18:40:45 +00:00
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
2017-11-04 00:55:16 +00:00
_fatalErrorMessage = std : : string ( " unexpected exception in main thread: " ) + e . what ( ) ;
2015-04-10 18:40:45 +00:00
} catch ( . . . ) {
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
2017-11-04 00:55:16 +00:00
_fatalErrorMessage = " unexpected exception in main thread: unknown exception " ;
2015-04-10 18:40:45 +00:00
}
2015-04-11 02:36:29 +00:00
try {
2017-06-05 19:15:28 +00:00
Mutex : : Lock _l ( _tcpConnections_m ) ;
2015-05-22 01:33:52 +00:00
while ( ! _tcpConnections . empty ( ) )
2015-05-22 22:46:06 +00:00
_phy . close ( ( * _tcpConnections . begin ( ) ) - > sock ) ;
2015-04-11 02:36:29 +00:00
} catch ( . . . ) { }
2015-04-15 00:57:51 +00:00
{
2016-06-14 17:09:26 +00:00
Mutex : : Lock _l ( _nets_m ) ;
_nets . clear ( ) ;
2015-04-15 00:57:51 +00:00
}
2017-01-12 00:34:33 +00:00
delete _updater ;
_updater = ( SoftwareUpdater * ) 0 ;
2015-04-10 18:40:45 +00:00
delete _node ;
_node = ( Node * ) 0 ;
return _termReason ;
}
2018-09-11 23:55:46 +00:00
void readLocalSettings ( )
2019-08-23 16:23:39 +00:00
{
2018-09-11 23:55:46 +00:00
// Read local configuration
std : : map < InetAddress , ZT_PhysicalPathConfiguration > ppc ;
// LEGACY: support old "trustedpaths" flat file
FILE * trustpaths = fopen ( ( _homePath + ZT_PATH_SEPARATOR_S " trustedpaths " ) . c_str ( ) , " r " ) ;
if ( trustpaths ) {
fprintf ( stderr , " WARNING: 'trustedpaths' flat file format is deprecated in favor of path definitions in local.conf " ZT_EOL_S ) ;
char buf [ 1024 ] ;
while ( fgets ( buf , sizeof ( buf ) , trustpaths ) ) {
int fno = 0 ;
char * saveptr = ( char * ) 0 ;
uint64_t trustedPathId = 0 ;
InetAddress trustedPathNetwork ;
for ( char * f = Utils : : stok ( buf , " = \r \n \t " , & saveptr ) ; ( f ) ; f = Utils : : stok ( ( char * ) 0 , " = \r \n \t " , & saveptr ) ) {
if ( fno = = 0 ) {
trustedPathId = Utils : : hexStrToU64 ( f ) ;
} else if ( fno = = 1 ) {
trustedPathNetwork = InetAddress ( f ) ;
} else break ;
+ + fno ;
}
if ( ( trustedPathId ! = 0 ) & & ( ( trustedPathNetwork . ss_family = = AF_INET ) | | ( trustedPathNetwork . ss_family = = AF_INET6 ) ) & & ( trustedPathNetwork . netmaskBits ( ) > 0 ) ) {
ppc [ trustedPathNetwork ] . trustedPathId = trustedPathId ;
ppc [ trustedPathNetwork ] . mtu = 0 ; // use default
}
}
fclose ( trustpaths ) ;
}
// Read local config file
Mutex : : Lock _l2 ( _localConfig_m ) ;
std : : string lcbuf ;
if ( OSUtils : : readFile ( ( _homePath + ZT_PATH_SEPARATOR_S " local.conf " ) . c_str ( ) , lcbuf ) ) {
2019-08-02 20:59:03 +00:00
if ( lcbuf . length ( ) > 0 ) {
try {
_localConfig = OSUtils : : jsonParse ( lcbuf ) ;
if ( ! _localConfig . is_object ( ) ) {
fprintf ( stderr , " ERROR: unable to parse local.conf (root element is not a JSON object) " ZT_EOL_S ) ;
exit ( 1 ) ;
}
} catch ( . . . ) {
fprintf ( stderr , " ERROR: unable to parse local.conf (invalid JSON) " ZT_EOL_S ) ;
2019-01-07 19:19:50 +00:00
exit ( 1 ) ;
2018-09-11 23:55:46 +00:00
}
}
}
2021-09-02 01:55:54 +00:00
// Make a copy so lookups don't modify in place;
json lc ( _localConfig ) ;
2018-09-11 23:55:46 +00:00
// Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere)
2021-09-02 01:55:54 +00:00
json & physical = lc [ " physical " ] ;
2018-09-11 23:55:46 +00:00
if ( physical . is_object ( ) ) {
for ( json : : iterator phy ( physical . begin ( ) ) ; phy ! = physical . end ( ) ; + + phy ) {
InetAddress net ( OSUtils : : jsonString ( phy . key ( ) , " " ) . c_str ( ) ) ;
if ( net ) {
if ( phy . value ( ) . is_object ( ) ) {
uint64_t tpid ;
if ( ( tpid = OSUtils : : jsonInt ( phy . value ( ) [ " trustedPathId " ] , 0ULL ) ) ! = 0ULL ) {
if ( ( net . ss_family = = AF_INET ) | | ( net . ss_family = = AF_INET6 ) )
ppc [ net ] . trustedPathId = tpid ;
}
ppc [ net ] . mtu = ( int ) OSUtils : : jsonInt ( phy . value ( ) [ " mtu " ] , 0ULL ) ; // 0 means use default
}
}
}
}
2021-09-02 01:55:54 +00:00
json & settings = lc [ " settings " ] ;
2018-09-11 23:55:46 +00:00
if ( settings . is_object ( ) ) {
// Allow controller DB path to be put somewhere else
const std : : string cdbp ( OSUtils : : jsonString ( settings [ " controllerDbPath " ] , " " ) ) ;
if ( cdbp . length ( ) > 0 )
_controllerDbPath = cdbp ;
2021-06-04 23:29:03 +00:00
_ssoRedirectURL = OSUtils : : jsonString ( settings [ " ssoRedirectURL " ] , " " ) ;
2020-05-11 22:03:56 +00:00
# ifdef ZT_CONTROLLER_USE_LIBPQ
2020-05-11 19:29:06 +00:00
// TODO: Redis config
2020-05-11 22:03:56 +00:00
json & redis = settings [ " redis " ] ;
if ( redis . is_object ( ) & & _rc = = NULL ) {
_rc = new RedisConfig ;
_rc - > hostname = OSUtils : : jsonString ( redis [ " hostname " ] , " " ) ;
2021-09-15 16:21:41 +00:00
_rc - > port = OSUtils : : jsonInt ( redis [ " port " ] , 0 ) ;
2020-05-11 22:03:56 +00:00
_rc - > password = OSUtils : : jsonString ( redis [ " password " ] , " " ) ;
_rc - > clusterMode = OSUtils : : jsonBool ( redis [ " clusterMode " ] , false ) ;
}
# endif
2019-03-05 23:11:50 +00:00
2018-09-11 23:55:46 +00:00
// Bind to wildcard instead of to specific interfaces (disables full tunnel capability)
json & bind = settings [ " bind " ] ;
if ( bind . is_array ( ) ) {
for ( unsigned long i = 0 ; i < bind . size ( ) ; + + i ) {
const std : : string ips ( OSUtils : : jsonString ( bind [ i ] , " " ) ) ;
if ( ips . length ( ) > 0 ) {
InetAddress ip ( ips . c_str ( ) ) ;
if ( ( ip . ss_family = = AF_INET ) | | ( ip . ss_family = = AF_INET6 ) )
explicitBind . push_back ( ip ) ;
}
}
}
}
// Set trusted paths if there are any
2020-07-16 16:31:56 +00:00
if ( ! ppc . empty ( ) ) {
2018-09-11 23:55:46 +00:00
for ( std : : map < InetAddress , ZT_PhysicalPathConfiguration > : : iterator i ( ppc . begin ( ) ) ; i ! = ppc . end ( ) ; + + i )
_node - > setPhysicalPathConfiguration ( reinterpret_cast < const struct sockaddr_storage * > ( & ( i - > first ) ) , & ( i - > second ) ) ;
}
}
2015-04-10 01:22:04 +00:00
virtual ReasonForTermination reasonForTermination ( ) const
2015-04-10 01:14:27 +00:00
{
Mutex : : Lock _l ( _termReason_m ) ;
return _termReason ;
}
2015-04-10 01:22:04 +00:00
virtual std : : string fatalErrorMessage ( ) const
2015-04-10 01:14:27 +00:00
{
2015-04-10 01:22:04 +00:00
Mutex : : Lock _l ( _termReason_m ) ;
return _fatalErrorMessage ;
2015-04-10 01:14:27 +00:00
}
2015-04-14 22:55:03 +00:00
virtual std : : string portDeviceName ( uint64_t nwid ) const
{
2016-06-14 17:09:26 +00:00
Mutex : : Lock _l ( _nets_m ) ;
std : : map < uint64_t , NetworkState > : : const_iterator n ( _nets . find ( nwid ) ) ;
2021-11-18 20:39:55 +00:00
if ( ( n ! = _nets . end ( ) ) & & ( n - > second . tap ( ) ) )
return n - > second . tap ( ) - > deviceName ( ) ;
2016-06-14 17:09:26 +00:00
else return std : : string ( ) ;
2015-04-14 22:55:03 +00:00
}
2017-05-04 22:26:44 +00:00
# ifdef ZT_SDK
2017-06-05 19:15:28 +00:00
virtual std : : string givenHomePath ( )
{
return _homePath ;
}
2017-05-04 22:26:44 +00:00
2019-01-14 19:34:46 +00:00
void getRoutes ( uint64_t nwid , void * routeArray , unsigned int * numRoutes )
2017-06-05 19:15:28 +00:00
{
2017-05-04 22:26:44 +00:00
Mutex : : Lock _l ( _nets_m ) ;
2017-08-10 07:59:15 +00:00
NetworkState & n = _nets [ nwid ] ;
2021-11-18 21:36:09 +00:00
* numRoutes = * numRoutes < n . config ( ) . routeCount ? * numRoutes : n . config ( ) . routeCount ;
2019-01-14 19:34:46 +00:00
for ( unsigned int i = 0 ; i < * numRoutes ; i + + ) {
ZT_VirtualNetworkRoute * vnr = ( ZT_VirtualNetworkRoute * ) routeArray ;
2021-11-18 21:36:09 +00:00
memcpy ( & vnr [ i ] , & ( n . config ( ) . routes [ i ] ) , sizeof ( ZT_VirtualNetworkRoute ) ) ;
2017-06-05 19:15:28 +00:00
}
}
2017-05-04 22:26:44 +00:00
2017-07-06 17:25:36 +00:00
virtual Node * getNode ( )
2017-05-04 22:26:44 +00:00
{
return _node ;
}
# endif // ZT_SDK
2015-04-10 01:14:27 +00:00
virtual void terminate ( )
{
_run_m . lock ( ) ;
2020-11-23 17:59:28 +00:00
2015-04-10 01:14:27 +00:00
_run = false ;
_run_m . unlock ( ) ;
_phy . whack ( ) ;
}
2016-06-21 21:58:30 +00:00
virtual bool getNetworkSettings ( const uint64_t nwid , NetworkSettings & settings ) const
{
Mutex : : Lock _l ( _nets_m ) ;
std : : map < uint64_t , NetworkState > : : const_iterator n ( _nets . find ( nwid ) ) ;
if ( n = = _nets . end ( ) )
return false ;
2021-11-18 20:39:55 +00:00
settings = n - > second . settings ( ) ;
2016-06-21 21:58:30 +00:00
return true ;
}
2016-06-21 23:52:49 +00:00
virtual bool setNetworkSettings ( const uint64_t nwid , const NetworkSettings & settings )
{
2017-06-02 03:32:43 +00:00
char nlcpath [ 4096 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( nlcpath , sizeof ( nlcpath ) , " %s " ZT_PATH_SEPARATOR_S " %.16llx.local.conf " , _networksPath . c_str ( ) , nwid ) ;
2016-06-21 23:52:49 +00:00
FILE * out = fopen ( nlcpath , " w " ) ;
if ( out ) {
2021-11-29 22:11:29 +00:00
fprintf ( out , " allowManaged=%d \n " , ( int ) settings . allowManaged ) ;
fprintf ( out , " allowGlobal=%d \n " , ( int ) settings . allowGlobal ) ;
fprintf ( out , " allowDefault=%d \n " , ( int ) settings . allowDefault ) ;
fprintf ( out , " allowDNS=%d \n " , ( int ) settings . allowDNS ) ;
2016-06-21 23:52:49 +00:00
fclose ( out ) ;
}
return true ;
}
2023-04-28 18:03:28 +00:00
// Internal HTTP Control Plane
void startHTTPControlPlane ( ) {
std : : vector < std : : string > noAuthEndpoints { " /sso " , " /health " } ;
2016-11-22 18:54:58 +00:00
2023-04-28 18:03:28 +00:00
auto setContent = [ = ] ( const httplib : : Request & req , httplib : : Response & res , std : : string content ) {
if ( req . has_param ( " jsonp " ) ) {
if ( content . length ( ) > 0 ) {
res . set_content ( req . get_param_value ( " jsonp " ) + " ( " + content + " ); " , " application/javascript " ) ;
} else {
res . set_content ( req . get_param_value ( " jsonp " ) + " (null); " , " application/javascript " ) ;
2017-03-07 21:53:11 +00:00
}
} else {
2023-04-28 18:03:28 +00:00
if ( content . length ( ) > 0 ) {
res . set_content ( content , " application/json " ) ;
} else {
res . set_content ( " {} " , " application/json " ) ;
2017-03-07 21:53:11 +00:00
}
2023-04-28 18:03:28 +00:00
}
} ;
2017-03-07 21:53:11 +00:00
2022-10-25 18:25:21 +00:00
2023-04-28 18:03:28 +00:00
auto authCheck = [ = ] ( const httplib : : Request & req , httplib : : Response & res ) {
std : : string r = req . remote_addr ;
InetAddress remoteAddr ( r . c_str ( ) ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
bool ipAllowed = false ;
bool isAuth = false ;
// If localhost, allow
if ( remoteAddr . ipScope ( ) = = InetAddress : : IP_SCOPE_LOOPBACK ) {
ipAllowed = true ;
}
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
if ( ! ipAllowed ) {
for ( auto i = _allowManagementFrom . begin ( ) ; i ! = _allowManagementFrom . end ( ) ; + + i ) {
if ( i - > containsAddress ( remoteAddr ) ) {
ipAllowed = true ;
break ;
}
}
}
2017-03-07 21:53:11 +00:00
2022-03-04 19:54:51 +00:00
2023-04-28 18:03:28 +00:00
if ( ipAllowed ) {
// auto-pass endpoints in `noAuthEndpoints`. No auth token required
if ( std : : find ( noAuthEndpoints . begin ( ) , noAuthEndpoints . end ( ) , req . path ) ! = noAuthEndpoints . end ( ) ) {
isAuth = true ;
}
if ( ! isAuth ) {
// check auth token
if ( req . has_header ( " x-zt1-auth " ) ) {
std : : string token = req . get_header_value ( " x-zt1-auth " ) ;
if ( token = = _authToken ) {
isAuth = true ;
}
} else if ( req . has_param ( " auth " ) ) {
std : : string token = req . get_param_value ( " auth " ) ;
if ( token = = _authToken ) {
isAuth = true ;
}
}
}
}
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
if ( ipAllowed & & isAuth ) {
return httplib : : Server : : HandlerResponse : : Unhandled ;
}
setContent ( req , res , " {} " ) ;
res . status = 401 ;
return httplib : : Server : : HandlerResponse : : Handled ;
} ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
_controlPlane . Get ( " /bond/show/([0-9a-fA-F]{10}) " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
if ( ! _node - > bondController ( ) - > inUse ( ) ) {
setContent ( req , res , " " ) ;
res . status = 400 ;
return ;
}
ZT_PeerList * pl = _node - > peers ( ) ;
if ( pl ) {
auto id = req . matches [ 1 ] ;
auto out = json : : object ( ) ;
uint64_t wantp = Utils : : hexStrToU64 ( id . str ( ) . c_str ( ) ) ;
for ( unsigned long i = 0 ; i < pl - > peerCount ; + + i ) {
if ( pl - > peers [ i ] . address = = wantp ) {
SharedPtr < Bond > bond = _node - > bondController ( ) - > getBondByPeerId ( wantp ) ;
if ( bond ) {
_peerToJson ( out , & ( pl - > peers [ i ] ) , bond , ( _tcpFallbackTunnel ! = ( TcpConnection * ) 0 ) ) ;
setContent ( req , res , out . dump ( ) ) ;
2022-05-12 02:59:58 +00:00
} else {
2023-04-28 18:03:28 +00:00
setContent ( req , res , " " ) ;
res . status = 400 ;
2022-05-12 02:59:58 +00:00
}
}
2023-04-28 18:03:28 +00:00
}
}
_node - > freeQueryResult ( ( void * ) pl ) ;
} ) ;
auto bondRotate = [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
if ( ! _node - > bondController ( ) - > inUse ( ) ) {
setContent ( req , res , " " ) ;
res . status = 400 ;
return ;
}
2022-03-10 20:59:26 +00:00
2023-04-28 18:03:28 +00:00
auto bondID = req . matches [ 1 ] ;
uint64_t id = Utils : : hexStrToU64 ( bondID . str ( ) . c_str ( ) ) ;
2022-05-13 00:00:43 +00:00
2023-04-28 18:03:28 +00:00
exit ( 0 ) ;
SharedPtr < Bond > bond = _node - > bondController ( ) - > getBondByPeerId ( id ) ;
if ( bond ) {
if ( bond - > abForciblyRotateLink ( ) ) {
res . status = 200 ;
2021-12-02 00:57:18 +00:00
} else {
2023-04-28 18:03:28 +00:00
res . status = 400 ;
2021-12-02 00:57:18 +00:00
}
2021-11-30 22:22:25 +00:00
} else {
2023-04-28 18:03:28 +00:00
fprintf ( stderr , " unable to find bond to peer %llx \n " , ( unsigned long long ) id ) ;
res . status = 400 ;
}
setContent ( req , res , " {} " ) ;
} ;
_controlPlane . Post ( " /bond/rotate/([0-9a-fA-F]{10}) " , bondRotate ) ;
_controlPlane . Put ( " /bond/rotate/([0-9a-fA-F]{10}) " , bondRotate ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
_controlPlane . Get ( " /config " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
std : : string config ;
{
Mutex : : Lock lc ( _localConfig_m ) ;
config = _localConfig . dump ( ) ;
}
if ( config = = " null " ) {
config = " {} " ;
}
setContent ( req , res , config ) ;
} ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
auto configPost = [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
json j ( OSUtils : : jsonParse ( req . body ) ) ;
if ( j . is_object ( ) ) {
Mutex : : Lock lcl ( _localConfig_m ) ;
json lc ( _localConfig ) ;
for ( json : : const_iterator s ( j . begin ( ) ) ; s ! = j . end ( ) ; + + s ) {
lc [ " settings " ] [ s . key ( ) ] = s . value ( ) ;
}
std : : string lcStr = OSUtils : : jsonDump ( lc , 4 ) ;
if ( OSUtils : : writeFile ( ( _homePath + ZT_PATH_SEPARATOR_S " local.conf " ) . c_str ( ) , lcStr ) ) {
_localConfig = lc ;
}
}
setContent ( req , res , " {} " ) ;
} ;
_controlPlane . Post ( " /config/settings " , configPost ) ;
_controlPlane . Put ( " /config/settings " , configPost ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
_controlPlane . Get ( " /health " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
json out = json : : object ( ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
char tmp [ 256 ] ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
ZT_NodeStatus status ;
_node - > status ( & status ) ;
out [ " online " ] = ( bool ) ( status . online ! = 0 ) ;
out [ " versionMajor " ] = ZEROTIER_ONE_VERSION_MAJOR ;
out [ " versionMinor " ] = ZEROTIER_ONE_VERSION_MINOR ;
out [ " versionRev " ] = ZEROTIER_ONE_VERSION_REVISION ;
out [ " versionBuild " ] = ZEROTIER_ONE_VERSION_BUILD ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %d.%d.%d " , ZEROTIER_ONE_VERSION_MAJOR , ZEROTIER_ONE_VERSION_MINOR , ZEROTIER_ONE_VERSION_REVISION ) ;
out [ " version " ] = tmp ;
out [ " clock " ] = OSUtils : : now ( ) ;
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /moon " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
std : : vector < World > moons ( _node - > moons ( ) ) ;
auto out = json : : array ( ) ;
for ( auto i = moons . begin ( ) ; i ! = moons . end ( ) ; + + i ) {
json mj ;
_moonToJson ( mj , * i ) ;
out . push_back ( mj ) ;
}
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /moon/([0-9a-fA-F]{10}) " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
std : : vector < World > moons ( _node - > moons ( ) ) ;
auto input = req . matches [ 1 ] ;
auto out = json : : object ( ) ;
const uint64_t id = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
for ( auto i = moons . begin ( ) ; i ! = moons . end ( ) ; + + i ) {
if ( i - > id ( ) = = id ) {
_moonToJson ( out , * i ) ;
break ;
}
}
setContent ( req , res , out . dump ( ) ) ;
} ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
auto moonPost = [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
auto input = req . matches [ 1 ] ;
uint64_t seed = 0 ;
try {
json j ( OSUtils : : jsonParse ( req . body ) ) ;
if ( j . is_object ( ) ) {
seed = Utils : : hexStrToU64 ( OSUtils : : jsonString ( j [ " seed " ] , " 0 " ) . c_str ( ) ) ;
2017-03-07 21:53:11 +00:00
}
2023-04-28 18:03:28 +00:00
} catch ( . . . ) {
// discard invalid JSON
}
std : : vector < World > moons ( _node - > moons ( ) ) ;
const uint64_t id = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
bool found = false ;
auto out = json : : object ( ) ;
for ( std : : vector < World > : : const_iterator m ( moons . begin ( ) ) ; m ! = moons . end ( ) ; + + m ) {
if ( m - > id ( ) = = id ) {
_moonToJson ( out , * m ) ;
found = true ;
break ;
2017-03-07 21:53:11 +00:00
}
2023-04-28 18:03:28 +00:00
}
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
if ( ! found & & seed ! = 0 ) {
char tmp [ 64 ] ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.16llx " , id ) ;
out [ " id " ] = tmp ;
out [ " roots " ] = json : : array ( ) ;
out [ " timestamp " ] = 0 ;
out [ " signature " ] = json ( ) ;
out [ " updatesMustBeSignedBy " ] = json ( ) ;
out [ " waiting " ] = true ;
_node - > orbit ( ( void * ) 0 , id , seed ) ;
}
setContent ( req , res , out . dump ( ) ) ;
} ;
_controlPlane . Post ( " /moon/([0-9a-fA-F]{10}) " , moonPost ) ;
_controlPlane . Put ( " /moon/([0-9a-fA-F]{10}) " , moonPost ) ;
_controlPlane . Delete ( " /moon/([0-9a-fA-F]{10}) " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
auto input = req . matches [ 1 ] ;
uint64_t id = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
auto out = json : : object ( ) ;
_node - > deorbit ( ( void * ) 0 , id ) ;
out [ " result " ] = true ;
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /network " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
Mutex : : Lock _l ( _nets_m ) ;
auto out = json : : array ( ) ;
for ( auto it = _nets . begin ( ) ; it ! = _nets . end ( ) ; + + it ) {
NetworkState & ns = it - > second ;
json nj ;
_networkToJson ( nj , ns ) ;
out . push_back ( nj ) ;
}
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /network/([0-9a-fA-F]{16}) " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
Mutex : : Lock _l ( _nets_m ) ;
auto input = req . matches [ 1 ] ;
const uint64_t nwid = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
if ( _nets . find ( nwid ) ! = _nets . end ( ) ) {
auto out = json : : object ( ) ;
NetworkState & ns = _nets [ nwid ] ;
_networkToJson ( out , ns ) ;
setContent ( req , res , out . dump ( ) ) ;
return ;
}
setContent ( req , res , " " ) ;
res . status = 404 ;
} ) ;
auto networkPost = [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
auto input = req . matches [ 1 ] ;
uint64_t wantnw = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
_node - > join ( wantnw , ( void * ) 0 , ( void * ) 0 ) ;
auto out = json : : object ( ) ;
Mutex : : Lock l ( _nets_m ) ;
if ( ! _nets . empty ( ) ) {
NetworkState & ns = _nets [ wantnw ] ;
try {
json j ( OSUtils : : jsonParse ( req . body ) ) ;
2017-03-07 21:53:11 +00:00
2023-04-28 18:03:28 +00:00
json & allowManaged = j [ " allowManaged " ] ;
if ( allowManaged . is_boolean ( ) ) {
ns . setAllowManaged ( ( bool ) allowManaged ) ;
}
json & allowGlobal = j [ " allowGlobal " ] ;
if ( allowGlobal . is_boolean ( ) ) {
ns . setAllowGlobal ( ( bool ) allowGlobal ) ;
}
json & allowDefault = j [ " allowDefault " ] ;
if ( allowDefault . is_boolean ( ) ) {
ns . setAllowDefault ( ( bool ) allowDefault ) ;
}
json & allowDNS = j [ " allowDNS " ] ;
if ( allowDNS . is_boolean ( ) ) {
ns . setAllowDNS ( ( bool ) allowDNS ) ;
}
} catch ( . . . ) {
// discard invalid JSON
}
setNetworkSettings ( wantnw , ns . settings ( ) ) ;
if ( ns . tap ( ) ) {
syncManagedStuff ( ns , true , true , true ) ;
}
_networkToJson ( out , ns ) ;
}
setContent ( req , res , out . dump ( ) ) ;
} ;
_controlPlane . Post ( " /network/([0-9a-fA-F]{16}) " , networkPost ) ;
_controlPlane . Put ( " /network/([0-9a-fA-F]){16} " , networkPost ) ;
_controlPlane . Delete ( " /network/([0-9a-fA-F]{16}) " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
auto input = req . matches [ 1 ] ;
auto out = json : : object ( ) ;
ZT_VirtualNetworkList * nws = _node - > networks ( ) ;
uint64_t wantnw = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
for ( unsigned long i = 0 ; i < nws - > networkCount ; + + i ) {
if ( nws - > networks [ i ] . nwid = = wantnw ) {
_node - > leave ( wantnw , ( void * * ) 0 , ( void * ) 0 ) ;
out [ " result " ] = true ;
}
}
_node - > freeQueryResult ( ( void * ) nws ) ;
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /peer " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
ZT_PeerList * pl = _node - > peers ( ) ;
auto out = nlohmann : : json : : array ( ) ;
for ( unsigned long i = 0 ; i < pl - > peerCount ; + + i ) {
nlohmann : : json pj ;
SharedPtr < Bond > bond = SharedPtr < Bond > ( ) ;
if ( pl - > peers [ i ] . isBonded ) {
const uint64_t id = pl - > peers [ i ] . address ;
bond = _node - > bondController ( ) - > getBondByPeerId ( id ) ;
}
_peerToJson ( pj , & ( pl - > peers [ i ] ) , bond , ( _tcpFallbackTunnel ! = ( TcpConnection * ) 0 ) ) ;
out . push_back ( pj ) ;
}
_node - > freeQueryResult ( ( void * ) pl ) ;
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /peer/([0-9a-fA-F]{10}) " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
ZT_PeerList * pl = _node - > peers ( ) ;
auto input = req . matches [ 1 ] ;
uint64_t wantp = Utils : : hexStrToU64 ( input . str ( ) . c_str ( ) ) ;
auto out = json : : object ( ) ;
for ( unsigned long i = 0 ; i < pl - > peerCount ; + + i ) {
if ( pl - > peers [ i ] . address = = wantp ) {
SharedPtr < Bond > bond = SharedPtr < Bond > ( ) ;
if ( pl - > peers [ i ] . isBonded ) {
bond = _node - > bondController ( ) - > getBondByPeerId ( wantp ) ;
}
_peerToJson ( out , & ( pl - > peers [ i ] ) , bond , ( _tcpFallbackTunnel ! = ( TcpConnection * ) 0 ) ) ;
break ;
}
}
_node - > freeQueryResult ( ( void * ) pl ) ;
setContent ( req , res , out . dump ( ) ) ;
} ) ;
_controlPlane . Get ( " /status " , [ & ] ( const httplib : : Request & req , httplib : : Response & res ) {
ZT_NodeStatus status ;
_node - > status ( & status ) ;
auto out = json : : object ( ) ;
char tmp [ 256 ] = { } ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %.10llx " , status . address ) ;
out [ " address " ] = tmp ;
out [ " publicIdentity " ] = status . publicIdentity ;
out [ " online " ] = ( bool ) ( status . online ! = 0 ) ;
out [ " tcpFallbackActive " ] = ( _tcpFallbackTunnel ! = ( TcpConnection * ) 0 ) ;
out [ " versionMajor " ] = ZEROTIER_ONE_VERSION_MAJOR ;
out [ " versionMinor " ] = ZEROTIER_ONE_VERSION_MINOR ;
out [ " versionRev " ] = ZEROTIER_ONE_VERSION_REVISION ;
out [ " versionBuild " ] = ZEROTIER_ONE_VERSION_BUILD ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " %d.%d.%d " , ZEROTIER_ONE_VERSION_MAJOR , ZEROTIER_ONE_VERSION_MINOR , ZEROTIER_ONE_VERSION_REVISION ) ;
out [ " version " ] = tmp ;
out [ " clock " ] = OSUtils : : now ( ) ;
{
Mutex : : Lock _l ( _localConfig_m ) ;
out [ " config " ] = _localConfig ;
}
json & settings = out [ " config " ] [ " settings " ] ;
settings [ " allowTcpFallbackRelay " ] = OSUtils : : jsonBool ( settings [ " allowTcpFallbackRelay " ] , _allowTcpFallbackRelay ) ;
settings [ " forceTcpRelay " ] = OSUtils : : jsonBool ( settings [ " forceTcpRelay " ] , _forceTcpRelay ) ;
settings [ " primaryPort " ] = OSUtils : : jsonInt ( settings [ " primaryPort " ] , ( uint64_t ) _primaryPort ) & 0xffff ;
settings [ " secondaryPort " ] = OSUtils : : jsonInt ( settings [ " secondaryPort " ] , ( uint64_t ) _secondaryPort ) & 0xffff ;
settings [ " tertiaryPort " ] = OSUtils : : jsonInt ( settings [ " tertiaryPort " ] , ( uint64_t ) _tertiaryPort ) & 0xffff ;
// Enumerate all local address/port pairs that this node is listening on
std : : vector < InetAddress > boundAddrs ( _binder . allBoundLocalInterfaceAddresses ( ) ) ;
auto boundAddrArray = json : : array ( ) ;
for ( int i = 0 ; i < boundAddrs . size ( ) ; i + + ) {
char ipBuf [ 64 ] = { 0 } ;
boundAddrs [ i ] . toString ( ipBuf ) ;
boundAddrArray . push_back ( ipBuf ) ;
}
settings [ " listeningOn " ] = boundAddrArray ;
// Enumerate all external address/port pairs that are reported for this node
std : : vector < InetAddress > surfaceAddrs = _node - > SurfaceAddresses ( ) ;
auto surfaceAddrArray = json : : array ( ) ;
for ( int i = 0 ; i < surfaceAddrs . size ( ) ; i + + ) {
char ipBuf [ 64 ] = { 0 } ;
surfaceAddrs [ i ] . toString ( ipBuf ) ;
surfaceAddrArray . push_back ( ipBuf ) ;
}
settings [ " surfaceAddresses " ] = surfaceAddrArray ;
# ifdef ZT_USE_MINIUPNPC
settings [ " portMappingEnabled " ] = OSUtils : : jsonBool ( settings [ " portMappingEnabled " ] , true ) ;
# else
settings [ " portMappingEnabled " ] = false ; // not supported in build
# endif
# ifndef ZT_SDK
settings [ " softwareUpdate " ] = OSUtils : : jsonString ( settings [ " softwareUpdate " ] , ZT_SOFTWARE_UPDATE_DEFAULT ) ;
settings [ " softwareUpdateChannel " ] = OSUtils : : jsonString ( settings [ " softwareUpdateChannel " ] , ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL ) ;
# endif
const World planet ( _node - > planet ( ) ) ;
out [ " planetWorldId " ] = planet . id ( ) ;
out [ " planetWorldTimestamp " ] = planet . timestamp ( ) ;
setContent ( req , res , out . dump ( ) ) ;
} ) ;
# if ZT_SSO_ENABLED
_controlPlane . Get ( " /sso " , [ this ] ( const httplib : : Request & req , httplib : : Response & res ) {
std : : string htmlTemplatePath = _homePath + ZT_PATH_SEPARATOR + " sso-auth.template.html " ;
std : : string htmlTemplate ;
if ( ! OSUtils : : readFile ( htmlTemplatePath . c_str ( ) , htmlTemplate ) ) {
htmlTemplate = ssoResponseTemplate ;
}
std : : string responseContentType = " text/html " ;
std : : string responseBody = " " ;
json outData ;
if ( req . has_param ( " error " ) ) {
std : : string error = req . get_param_value ( " error " ) ;
std : : string desc = req . get_param_value ( " error_description " ) ;
json data ;
outData [ " isError " ] = true ;
outData [ " messageText " ] = ( std : : string ( " ERROR " ) + error + std : : string ( " : " ) + desc ) ;
responseBody = inja : : render ( htmlTemplate , outData ) ;
res . set_content ( responseBody , responseContentType ) ;
res . status = 500 ;
return ;
}
// SSO redirect handling
std : : string state = req . get_param_value ( " state " ) ;
char * nwid = zeroidc : : zeroidc_network_id_from_state ( state . c_str ( ) ) ;
outData [ " networkId " ] = std : : string ( nwid ) ;
const uint64_t id = Utils : : hexStrToU64 ( nwid ) ;
zeroidc : : free_cstr ( nwid ) ;
Mutex : : Lock l ( _nets_m ) ;
if ( _nets . find ( id ) ! = _nets . end ( ) ) {
NetworkState & ns = _nets [ id ] ;
std : : string code = req . get_param_value ( " code " ) ;
char * ret = ns . doTokenExchange ( code . c_str ( ) ) ;
json ssoResult = json : : parse ( ret ) ;
if ( ssoResult . is_object ( ) ) {
if ( ssoResult . contains ( " errorMessage " ) ) {
outData [ " isError " ] = true ;
outData [ " messageText " ] = ssoResult [ " errorMessage " ] ;
responseBody = inja : : render ( htmlTemplate , outData ) ;
res . set_content ( responseBody , responseContentType ) ;
res . status = 500 ;
} else {
outData [ " isError " ] = false ;
outData [ " messageText " ] = " Authentication Successful. You may now access the network. " ;
responseBody = inja : : render ( htmlTemplate , outData ) ;
res . set_content ( responseBody , responseContentType ) ;
}
} else {
// not an object? We got a problem
outData [ " isError " ] = true ;
outData [ " messageText " ] = " ERROR: Unkown SSO response. Please contact your administrator. " ;
responseBody = inja : : render ( htmlTemplate , outData ) ;
res . set_content ( responseBody , responseContentType ) ;
res . status = 500 ;
}
zeroidc : : free_cstr ( ret ) ;
}
} ) ;
# endif
_controlPlane . Get ( " /metrics " , [ this ] ( const httplib : : Request & req , httplib : : Response & res ) {
std : : string statspath = _homePath + ZT_PATH_SEPARATOR + " metrics.prom " ;
std : : string metrics ;
if ( OSUtils : : readFile ( statspath . c_str ( ) , metrics ) ) {
res . set_content ( metrics , " text/plain " ) ;
} else {
res . set_content ( " {} " , " application/json " ) ;
res . status = 500 ;
}
} ) ;
_controlPlane . set_exception_handler ( [ & ] ( const httplib : : Request & req , httplib : : Response & res , std : : exception_ptr ep ) {
char buf [ 1024 ] ;
auto fmt = " { \" error \" : %d, \" description \" : \" %s \" } " ;
try {
std : : rethrow_exception ( ep ) ;
} catch ( std : : exception & e ) {
snprintf ( buf , sizeof ( buf ) , fmt , 500 , e . what ( ) ) ;
} catch ( . . . ) {
snprintf ( buf , sizeof ( buf ) , fmt , 500 , " Unknown Exception " ) ;
}
setContent ( req , res , buf ) ;
res . status = 500 ;
} ) ;
if ( _controller ) {
_controller - > configureHTTPControlPlane ( _controlPlane , setContent ) ;
2017-03-07 21:53:11 +00:00
}
2023-04-28 18:03:28 +00:00
_controlPlane . set_pre_routing_handler ( authCheck ) ;
# if ZT_DEBUG==1
_controlPlane . set_logger ( [ ] ( const httplib : : Request & req , const httplib : : Response & res ) {
fprintf ( stderr , " %s " , http_log ( req , res ) . c_str ( ) ) ;
} ) ;
# endif
2023-05-02 23:46:06 +00:00
if ( _primaryPort = = 0 ) {
fprintf ( stderr , " unable to determine local control port " ) ;
exit ( - 1 ) ;
}
if ( ! _controlPlane . bind_to_port ( " 0.0.0.0 " , _primaryPort ) ) {
fprintf ( stderr , " Error binding control plane to port %d \n " , _primaryPort ) ;
exit ( - 1 ) ;
}
2023-04-28 18:03:28 +00:00
_serverThread = std : : thread ( [ & ] {
fprintf ( stderr , " Starting Control Plane... \n " ) ;
2023-05-02 23:46:06 +00:00
if ( ! _controlPlane . listen_after_bind ( ) ) {
fprintf ( stderr , " Error on listen_after_bind() \n " ) ;
}
2023-04-28 18:03:28 +00:00
fprintf ( stderr , " Control Plane Stopped \n " ) ;
} ) ;
}
2015-05-22 21:52:23 +00:00
2016-11-22 22:23:13 +00:00
// Must be called after _localConfig is read or modified
2016-11-22 18:54:58 +00:00
void applyLocalConfig ( )
2015-04-10 01:14:27 +00:00
{
2016-11-22 18:54:58 +00:00
Mutex : : Lock _l ( _localConfig_m ) ;
2017-03-11 06:02:08 +00:00
json lc ( _localConfig ) ;
2016-11-22 18:54:58 +00:00
_v4Hints . clear ( ) ;
_v6Hints . clear ( ) ;
_v4Blacklists . clear ( ) ;
_v6Blacklists . clear ( ) ;
2017-03-11 06:02:08 +00:00
json & virt = lc [ " virtual " ] ;
2016-11-22 18:54:58 +00:00
if ( virt . is_object ( ) ) {
for ( json : : iterator v ( virt . begin ( ) ) ; v ! = virt . end ( ) ; + + v ) {
const std : : string nstr = v . key ( ) ;
if ( ( nstr . length ( ) = = ZT_ADDRESS_LENGTH_HEX ) & & ( v . value ( ) . is_object ( ) ) ) {
2017-02-04 08:23:31 +00:00
const Address ztaddr ( Utils : : hexStrToU64 ( nstr . c_str ( ) ) ) ;
2016-11-22 18:54:58 +00:00
if ( ztaddr ) {
const uint64_t ztaddr2 = ztaddr . toInt ( ) ;
std : : vector < InetAddress > & v4h = _v4Hints [ ztaddr2 ] ;
std : : vector < InetAddress > & v6h = _v6Hints [ ztaddr2 ] ;
std : : vector < InetAddress > & v4b = _v4Blacklists [ ztaddr2 ] ;
std : : vector < InetAddress > & v6b = _v6Blacklists [ ztaddr2 ] ;
json & tryAddrs = v . value ( ) [ " try " ] ;
if ( tryAddrs . is_array ( ) ) {
for ( unsigned long i = 0 ; i < tryAddrs . size ( ) ; + + i ) {
2017-07-06 23:11:11 +00:00
const InetAddress ip ( OSUtils : : jsonString ( tryAddrs [ i ] , " " ) . c_str ( ) ) ;
2016-11-22 18:54:58 +00:00
if ( ip . ss_family = = AF_INET )
v4h . push_back ( ip ) ;
else if ( ip . ss_family = = AF_INET6 )
v6h . push_back ( ip ) ;
}
}
json & blAddrs = v . value ( ) [ " blacklist " ] ;
if ( blAddrs . is_array ( ) ) {
for ( unsigned long i = 0 ; i < blAddrs . size ( ) ; + + i ) {
2017-11-27 23:31:25 +00:00
const InetAddress ip ( OSUtils : : jsonString ( blAddrs [ i ] , " " ) . c_str ( ) ) ;
2016-11-22 18:54:58 +00:00
if ( ip . ss_family = = AF_INET )
v4b . push_back ( ip ) ;
else if ( ip . ss_family = = AF_INET6 )
v6b . push_back ( ip ) ;
}
}
2015-04-10 01:14:27 +00:00
2016-11-22 18:54:58 +00:00
if ( v4h . empty ( ) ) _v4Hints . erase ( ztaddr2 ) ;
if ( v6h . empty ( ) ) _v6Hints . erase ( ztaddr2 ) ;
if ( v4b . empty ( ) ) _v4Blacklists . erase ( ztaddr2 ) ;
if ( v6b . empty ( ) ) _v6Blacklists . erase ( ztaddr2 ) ;
}
}
}
}
2016-06-21 21:58:30 +00:00
2016-11-22 18:54:58 +00:00
_globalV4Blacklist . clear ( ) ;
_globalV6Blacklist . clear ( ) ;
2017-03-11 06:02:08 +00:00
json & physical = lc [ " physical " ] ;
2016-11-22 18:54:58 +00:00
if ( physical . is_object ( ) ) {
for ( json : : iterator phy ( physical . begin ( ) ) ; phy ! = physical . end ( ) ; + + phy ) {
2017-07-06 23:11:11 +00:00
const InetAddress net ( OSUtils : : jsonString ( phy . key ( ) , " " ) . c_str ( ) ) ;
2016-11-22 18:54:58 +00:00
if ( ( net ) & & ( net . netmaskBits ( ) > 0 ) ) {
if ( phy . value ( ) . is_object ( ) ) {
2017-01-10 21:51:10 +00:00
if ( OSUtils : : jsonBool ( phy . value ( ) [ " blacklist " ] , false ) ) {
2016-11-22 18:54:58 +00:00
if ( net . ss_family = = AF_INET )
_globalV4Blacklist . push_back ( net ) ;
else if ( net . ss_family = = AF_INET6 )
_globalV6Blacklist . push_back ( net ) ;
}
}
}
}
}
2016-06-21 23:52:49 +00:00
2016-12-13 00:25:41 +00:00
_allowManagementFrom . clear ( ) ;
2016-12-12 22:43:09 +00:00
_interfacePrefixBlacklist . clear ( ) ;
2016-06-21 23:52:49 +00:00
2017-03-11 06:02:08 +00:00
json & settings = lc [ " settings " ] ;
2020-05-12 08:35:48 +00:00
if ( ! _node - > bondController ( ) - > inUse ( ) ) {
2022-09-20 21:27:34 +00:00
_node - > bondController ( ) - > setBinder ( & _binder ) ;
2020-05-12 08:35:48 +00:00
// defaultBondingPolicy
std : : string defaultBondingPolicyStr ( OSUtils : : jsonString ( settings [ " defaultBondingPolicy " ] , " " ) ) ;
int defaultBondingPolicy = _node - > bondController ( ) - > getPolicyCodeByStr ( defaultBondingPolicyStr ) ;
_node - > bondController ( ) - > setBondingLayerDefaultPolicy ( defaultBondingPolicy ) ;
_node - > bondController ( ) - > setBondingLayerDefaultPolicyStr ( defaultBondingPolicyStr ) ; // Used if custom policy
// Custom Policies
json & customBondingPolicies = settings [ " policies " ] ;
for ( json : : iterator policyItr = customBondingPolicies . begin ( ) ; policyItr ! = customBondingPolicies . end ( ) ; + + policyItr ) {
// Custom Policy
std : : string customPolicyStr ( policyItr . key ( ) ) ;
json & customPolicy = policyItr . value ( ) ;
std : : string basePolicyStr ( OSUtils : : jsonString ( customPolicy [ " basePolicy " ] , " " ) ) ;
2020-11-23 17:59:28 +00:00
if ( basePolicyStr . empty ( ) ) {
fprintf ( stderr , " error: no base policy was specified for custom policy (%s) \n " , customPolicyStr . c_str ( ) ) ;
}
2021-12-14 19:49:43 +00:00
int basePolicyCode = _node - > bondController ( ) - > getPolicyCodeByStr ( basePolicyStr ) ;
if ( basePolicyCode = = ZT_BOND_POLICY_NONE ) {
2020-05-12 08:35:48 +00:00
fprintf ( stderr , " error: custom policy (%s) is invalid, unknown base policy (%s). \n " ,
customPolicyStr . c_str ( ) , basePolicyStr . c_str ( ) ) ;
continue ;
2021-09-02 04:37:49 +00:00
} if ( _node - > bondController ( ) - > getPolicyCodeByStr ( customPolicyStr ) ! = ZT_BOND_POLICY_NONE ) {
2020-05-12 08:35:48 +00:00
fprintf ( stderr , " error: custom policy (%s) will be ignored, cannot use standard policy names for custom policies. \n " ,
customPolicyStr . c_str ( ) ) ;
continue ;
}
// New bond, used as a copy template for new instances
2020-05-27 00:57:37 +00:00
SharedPtr < Bond > newTemplateBond = new Bond ( NULL , basePolicyStr , customPolicyStr , SharedPtr < Peer > ( ) ) ;
2021-12-14 19:49:43 +00:00
newTemplateBond - > setPolicy ( basePolicyCode ) ;
2022-10-10 06:07:16 +00:00
// Custom link quality spec
json & linkQualitySpec = customPolicy [ " linkQuality " ] ;
if ( linkQualitySpec . size ( ) = = ZT_QOS_PARAMETER_SIZE ) {
float weights [ ZT_QOS_PARAMETER_SIZE ] = { } ;
weights [ ZT_QOS_LAT_MAX_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " lat_max " ] , 0.0 ) ;
weights [ ZT_QOS_PDV_MAX_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " pdv_max " ] , 0.0 ) ;
weights [ ZT_QOS_PLR_MAX_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " plr_max " ] , 0.0 ) ;
weights [ ZT_QOS_PER_MAX_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " per_max " ] , 0.0 ) ;
weights [ ZT_QOS_LAT_WEIGHT_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " lat_weight " ] , 0.0 ) ;
weights [ ZT_QOS_PDV_WEIGHT_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " pdv_weight " ] , 0.0 ) ;
weights [ ZT_QOS_PLR_WEIGHT_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " plr_weight " ] , 0.0 ) ;
weights [ ZT_QOS_PER_WEIGHT_IDX ] = ( float ) OSUtils : : jsonDouble ( linkQualitySpec [ " per_weight " ] , 0.0 ) ;
newTemplateBond - > setUserLinkQualitySpec ( weights , ZT_QOS_PARAMETER_SIZE ) ;
2020-05-12 08:35:48 +00:00
}
// Bond-specific properties
newTemplateBond - > setUpDelay ( OSUtils : : jsonInt ( customPolicy [ " upDelay " ] , - 1 ) ) ;
newTemplateBond - > setDownDelay ( OSUtils : : jsonInt ( customPolicy [ " downDelay " ] , - 1 ) ) ;
2021-12-14 19:49:43 +00:00
newTemplateBond - > setFailoverInterval ( OSUtils : : jsonInt ( customPolicy [ " failoverInterval " ] , ZT_BOND_FAILOVER_DEFAULT_INTERVAL ) ) ;
2020-06-17 21:54:13 +00:00
newTemplateBond - > setPacketsPerLink ( OSUtils : : jsonInt ( customPolicy [ " packetsPerLink " ] , - 1 ) ) ;
// Policy-Specific link set
json & links = customPolicy [ " links " ] ;
for ( json : : iterator linkItr = links . begin ( ) ; linkItr ! = links . end ( ) ; + + linkItr ) {
std : : string linkNameStr ( linkItr . key ( ) ) ;
json & link = linkItr . value ( ) ;
bool enabled = OSUtils : : jsonInt ( link [ " enabled " ] , true ) ;
2022-10-10 06:07:16 +00:00
uint32_t capacity = OSUtils : : jsonInt ( link [ " capacity " ] , 0 ) ;
2020-06-17 21:54:13 +00:00
uint8_t ipvPref = OSUtils : : jsonInt ( link [ " ipvPref " ] , 0 ) ;
2023-01-12 04:12:15 +00:00
uint16_t mtu = OSUtils : : jsonInt ( link [ " mtu " ] , 0 ) ;
2020-06-17 21:54:13 +00:00
std : : string failoverToStr ( OSUtils : : jsonString ( link [ " failoverTo " ] , " " ) ) ;
2020-05-12 08:35:48 +00:00
// Mode
2020-06-17 21:54:13 +00:00
std : : string linkModeStr ( OSUtils : : jsonString ( link [ " mode " ] , " spare " ) ) ;
2021-09-02 04:37:49 +00:00
uint8_t linkMode = ZT_BOND_SLAVE_MODE_SPARE ;
if ( linkModeStr = = " primary " ) { linkMode = ZT_BOND_SLAVE_MODE_PRIMARY ; }
if ( linkModeStr = = " spare " ) { linkMode = ZT_BOND_SLAVE_MODE_SPARE ; }
2020-05-12 08:35:48 +00:00
// ipvPref
if ( ( ipvPref ! = 0 ) & & ( ipvPref ! = 4 ) & & ( ipvPref ! = 6 ) & & ( ipvPref ! = 46 ) & & ( ipvPref ! = 64 ) ) {
2020-06-17 21:54:13 +00:00
fprintf ( stderr , " error: invalid ipvPref value (%d), link disabled. \n " , ipvPref ) ;
2020-05-12 08:35:48 +00:00
enabled = false ;
}
2021-09-02 04:37:49 +00:00
if ( linkMode = = ZT_BOND_SLAVE_MODE_SPARE & & failoverToStr . length ( ) ) {
2020-06-17 21:54:13 +00:00
fprintf ( stderr , " error: cannot specify failover links for spares, link disabled. \n " ) ;
2020-05-12 08:35:48 +00:00
failoverToStr = " " ;
enabled = false ;
}
2023-01-12 04:12:15 +00:00
_node - > bondController ( ) - > addCustomLink ( customPolicyStr , new Link ( linkNameStr , ipvPref , mtu , capacity , enabled , linkMode , failoverToStr ) ) ;
2020-05-12 08:35:48 +00:00
}
2020-06-17 21:54:13 +00:00
std : : string linkSelectMethodStr ( OSUtils : : jsonString ( customPolicy [ " activeReselect " ] , " optimize " ) ) ;
2020-08-25 01:56:49 +00:00
if ( linkSelectMethodStr = = " always " ) {
2021-09-02 04:37:49 +00:00
newTemplateBond - > setLinkSelectMethod ( ZT_BOND_RESELECTION_POLICY_ALWAYS ) ;
2020-08-25 01:56:49 +00:00
}
if ( linkSelectMethodStr = = " better " ) {
2021-09-02 04:37:49 +00:00
newTemplateBond - > setLinkSelectMethod ( ZT_BOND_RESELECTION_POLICY_BETTER ) ;
2020-08-25 01:56:49 +00:00
}
if ( linkSelectMethodStr = = " failure " ) {
2021-09-02 04:37:49 +00:00
newTemplateBond - > setLinkSelectMethod ( ZT_BOND_RESELECTION_POLICY_FAILURE ) ;
2020-08-25 01:56:49 +00:00
}
if ( linkSelectMethodStr = = " optimize " ) {
2021-09-02 04:37:49 +00:00
newTemplateBond - > setLinkSelectMethod ( ZT_BOND_RESELECTION_POLICY_OPTIMIZE ) ;
2020-08-25 01:56:49 +00:00
}
2020-06-17 21:54:13 +00:00
if ( newTemplateBond - > getLinkSelectMethod ( ) < 0 | | newTemplateBond - > getLinkSelectMethod ( ) > 3 ) {
fprintf ( stderr , " warning: invalid value (%s) for linkSelectMethod, assuming mode: always \n " , linkSelectMethodStr . c_str ( ) ) ;
2020-05-12 08:35:48 +00:00
}
if ( ! _node - > bondController ( ) - > addCustomPolicy ( newTemplateBond ) ) {
fprintf ( stderr , " error: a custom policy of this name (%s) already exists. \n " , customPolicyStr . c_str ( ) ) ;
}
}
// Peer-specific bonding
json & peerSpecificBonds = settings [ " peerSpecificBonds " ] ;
for ( json : : iterator peerItr = peerSpecificBonds . begin ( ) ; peerItr ! = peerSpecificBonds . end ( ) ; + + peerItr ) {
_node - > bondController ( ) - > assignBondingPolicyToPeer ( std : : stoull ( peerItr . key ( ) , 0 , 16 ) , peerItr . value ( ) ) ;
}
// Check settings
if ( defaultBondingPolicyStr . length ( ) & & ! defaultBondingPolicy & & ! _node - > bondController ( ) - > inUse ( ) ) {
2020-11-30 00:57:30 +00:00
fprintf ( stderr , " error: unknown policy (%s) specified by defaultBondingPolicy, bond disabled. \n " , defaultBondingPolicyStr . c_str ( ) ) ;
2020-05-12 08:35:48 +00:00
}
}
// bondingPolicy cannot be used with allowTcpFallbackRelay
2022-04-28 18:12:04 +00:00
_allowTcpFallbackRelay = OSUtils : : jsonBool ( settings [ " allowTcpFallbackRelay " ] , true ) ;
2023-01-11 00:01:07 +00:00
_forceTcpRelay = OSUtils : : jsonBool ( settings [ " forceTcpRelay " ] , false ) ;
2022-04-28 18:05:54 +00:00
# ifdef ZT_TCP_FALLBACK_RELAY
2022-12-01 23:12:54 +00:00
_fallbackRelayAddress = InetAddress ( OSUtils : : jsonString ( settings [ " tcpFallbackRelay " ] , ZT_TCP_FALLBACK_RELAY ) . c_str ( ) ) ;
2022-04-28 18:05:54 +00:00
# endif
2017-03-11 06:02:08 +00:00
_primaryPort = ( unsigned int ) OSUtils : : jsonInt ( settings [ " primaryPort " ] , ( uint64_t ) _primaryPort ) & 0xffff ;
2019-07-09 17:31:03 +00:00
_allowSecondaryPort = OSUtils : : jsonBool ( settings [ " allowSecondaryPort " ] , true ) ;
2018-09-10 20:06:05 +00:00
_secondaryPort = ( unsigned int ) OSUtils : : jsonInt ( settings [ " secondaryPort " ] , 0 ) ;
_tertiaryPort = ( unsigned int ) OSUtils : : jsonInt ( settings [ " tertiaryPort " ] , 0 ) ;
if ( _secondaryPort ! = 0 | | _tertiaryPort ! = 0 ) {
2021-08-31 20:47:00 +00:00
fprintf ( stderr , " WARNING: using manually-specified secondary and/or tertiary ports. This can cause NAT issues. " ZT_EOL_S ) ;
2018-09-10 20:06:05 +00:00
}
2017-03-11 06:02:08 +00:00
_portMappingEnabled = OSUtils : : jsonBool ( settings [ " portMappingEnabled " ] , true ) ;
2022-12-05 21:21:05 +00:00
_node - > setLowBandwidthMode ( OSUtils : : jsonBool ( settings [ " lowBandwidthMode " ] , false ) ) ;
2017-03-11 06:02:08 +00:00
2017-05-04 22:26:44 +00:00
# ifndef ZT_SDK
2017-03-11 06:02:08 +00:00
const std : : string up ( OSUtils : : jsonString ( settings [ " softwareUpdate " ] , ZT_SOFTWARE_UPDATE_DEFAULT ) ) ;
const bool udist = OSUtils : : jsonBool ( settings [ " softwareUpdateDist " ] , false ) ;
if ( ( ( up = = " apply " ) | | ( up = = " download " ) ) | | ( udist ) ) {
if ( ! _updater )
_updater = new SoftwareUpdater ( * _node , _homePath ) ;
_updateAutoApply = ( up = = " apply " ) ;
_updater - > setUpdateDistribution ( udist ) ;
_updater - > setChannel ( OSUtils : : jsonString ( settings [ " softwareUpdateChannel " ] , ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL ) ) ;
} else {
delete _updater ;
_updater = ( SoftwareUpdater * ) 0 ;
_updateAutoApply = false ;
2016-06-21 23:52:49 +00:00
}
2017-05-04 22:26:44 +00:00
# endif
2016-06-21 23:52:49 +00:00
2017-03-11 06:02:08 +00:00
json & ignoreIfs = settings [ " interfacePrefixBlacklist " ] ;
if ( ignoreIfs . is_array ( ) ) {
for ( unsigned long i = 0 ; i < ignoreIfs . size ( ) ; + + i ) {
const std : : string tmp ( OSUtils : : jsonString ( ignoreIfs [ i ] , " " ) ) ;
if ( tmp . length ( ) > 0 )
_interfacePrefixBlacklist . push_back ( tmp ) ;
2016-12-12 22:43:09 +00:00
}
2017-03-11 06:02:08 +00:00
}
2016-06-21 23:52:49 +00:00
2017-03-11 06:02:08 +00:00
json & amf = settings [ " allowManagementFrom " ] ;
if ( amf . is_array ( ) ) {
for ( unsigned long i = 0 ; i < amf . size ( ) ; + + i ) {
2017-07-06 23:11:11 +00:00
const InetAddress nw ( OSUtils : : jsonString ( amf [ i ] , " " ) . c_str ( ) ) ;
2017-03-11 06:02:08 +00:00
if ( nw )
_allowManagementFrom . push_back ( nw ) ;
2016-12-13 00:25:41 +00:00
}
2016-11-22 18:54:58 +00:00
}
2016-06-21 23:52:49 +00:00
}
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
json & vault = settings [ " vault " ] ;
if ( vault . is_object ( ) ) {
const std : : string url ( OSUtils : : jsonString ( vault [ " vaultURL " ] , " " ) . c_str ( ) ) ;
if ( ! url . empty ( ) ) {
_vaultURL = url ;
}
const std : : string token ( OSUtils : : jsonString ( vault [ " vaultToken " ] , " " ) . c_str ( ) ) ;
if ( ! token . empty ( ) ) {
_vaultToken = token ;
}
const std : : string path ( OSUtils : : jsonString ( vault [ " vaultPath " ] , " " ) . c_str ( ) ) ;
if ( ! path . empty ( ) ) {
_vaultPath = path ;
}
}
// also check environment variables for values. Environment variables
// will override local.conf variables
const std : : string envURL ( getenv ( " VAULT_ADDR " ) ) ;
if ( ! envURL . empty ( ) ) {
_vaultURL = envURL ;
}
const std : : string envToken ( getenv ( " VAULT_TOKEN " ) ) ;
if ( ! envToken . empty ( ) ) {
_vaultToken = envToken ;
}
const std : : string envPath ( getenv ( " VAULT_PATH " ) ) ;
if ( ! envPath . empty ( ) ) {
_vaultPath = envPath ;
}
if ( ! _vaultURL . empty ( ) & & ! _vaultToken . empty ( ) ) {
_vaultEnabled = true ;
}
# endif
2016-06-17 20:14:48 +00:00
// Checks if a managed IP or route target is allowed
2016-07-12 15:42:36 +00:00
bool checkIfManagedIsAllowed ( const NetworkState & n , const InetAddress & target )
2016-06-17 20:14:48 +00:00
{
2021-11-18 20:39:55 +00:00
if ( ! n . allowManaged ( ) )
2016-06-17 20:14:48 +00:00
return false ;
2017-01-22 22:02:34 +00:00
2021-11-18 20:39:55 +00:00
if ( ! n . allowManagedWhitelist ( ) . empty ( ) ) {
2017-01-22 22:02:34 +00:00
bool allowed = false ;
2021-11-18 20:39:55 +00:00
for ( InetAddress addr : n . allowManagedWhitelist ( ) ) {
2017-01-22 22:02:34 +00:00
if ( addr . containsAddress ( target ) & & addr . netmaskBits ( ) < = target . netmaskBits ( ) ) {
allowed = true ;
break ;
}
}
if ( ! allowed ) return false ;
}
2016-07-12 15:42:36 +00:00
if ( target . isDefaultRoute ( ) )
2021-11-18 20:39:55 +00:00
return n . allowDefault ( ) ;
2016-07-12 15:42:36 +00:00
switch ( target . ipScope ( ) ) {
2016-06-17 20:14:48 +00:00
case InetAddress : : IP_SCOPE_NONE :
case InetAddress : : IP_SCOPE_MULTICAST :
case InetAddress : : IP_SCOPE_LOOPBACK :
case InetAddress : : IP_SCOPE_LINK_LOCAL :
return false ;
case InetAddress : : IP_SCOPE_GLOBAL :
2021-11-18 20:39:55 +00:00
return n . allowGlobal ( ) ;
2016-06-17 20:14:48 +00:00
default :
return true ;
}
}
2016-07-12 22:00:30 +00:00
// Match only an IP from a vector of IPs -- used in syncManagedStuff()
2020-11-13 21:02:59 +00:00
inline bool matchIpOnly ( const std : : set < InetAddress > & ips , const InetAddress & ip ) const
2016-07-12 22:00:30 +00:00
{
2020-11-13 21:02:59 +00:00
for ( std : : set < InetAddress > : : const_iterator i ( ips . begin ( ) ) ; i ! = ips . end ( ) ; + + i ) {
2016-07-12 22:00:30 +00:00
if ( i - > ipsEqual ( ip ) )
return true ;
}
return false ;
}
2016-06-17 20:14:48 +00:00
// Apply or update managed IPs for a configured network (be sure n.tap exists)
2020-07-31 18:42:03 +00:00
void syncManagedStuff ( NetworkState & n , bool syncIps , bool syncRoutes , bool syncDns )
2016-06-17 20:14:48 +00:00
{
2017-07-06 23:11:11 +00:00
char ipbuf [ 64 ] ;
2016-06-21 23:52:49 +00:00
// assumes _nets_m is locked
2016-06-17 20:14:48 +00:00
if ( syncIps ) {
std : : vector < InetAddress > newManagedIps ;
2021-11-18 20:39:55 +00:00
newManagedIps . reserve ( n . config ( ) . assignedAddressCount ) ;
2023-03-07 21:50:34 +00:00
# ifdef __APPLE__
std : : vector < InetAddress > newManagedIps2 ;
newManagedIps2 . reserve ( n . config ( ) . assignedAddressCount ) ;
# endif
2021-11-18 20:39:55 +00:00
for ( unsigned int i = 0 ; i < n . config ( ) . assignedAddressCount ; + + i ) {
const InetAddress * ii = reinterpret_cast < const InetAddress * > ( & ( n . config ( ) . assignedAddresses [ i ] ) ) ;
2016-06-17 20:14:48 +00:00
if ( checkIfManagedIsAllowed ( n , * ii ) )
newManagedIps . push_back ( * ii ) ;
}
std : : sort ( newManagedIps . begin ( ) , newManagedIps . end ( ) ) ;
newManagedIps . erase ( std : : unique ( newManagedIps . begin ( ) , newManagedIps . end ( ) ) , newManagedIps . end ( ) ) ;
2021-11-18 20:39:55 +00:00
for ( std : : vector < InetAddress > : : iterator ip ( n . managedIps ( ) . begin ( ) ) ; ip ! = n . managedIps ( ) . end ( ) ; + + ip ) {
2016-06-17 20:14:48 +00:00
if ( std : : find ( newManagedIps . begin ( ) , newManagedIps . end ( ) , * ip ) = = newManagedIps . end ( ) ) {
2021-11-18 20:39:55 +00:00
if ( ! n . tap ( ) - > removeIp ( * ip ) )
2017-07-06 23:11:11 +00:00
fprintf ( stderr , " ERROR: unable to remove ip address %s " ZT_EOL_S , ip - > toString ( ipbuf ) ) ;
2022-12-19 21:26:29 +00:00
# ifdef __WINDOWS__
WinFWHelper : : removeICMPRule ( * ip , n . config ( ) . nwid ) ;
# endif
2016-06-17 20:14:48 +00:00
}
}
2022-04-01 05:01:50 +00:00
2023-03-07 21:50:34 +00:00
2016-07-12 16:43:12 +00:00
for ( std : : vector < InetAddress > : : iterator ip ( newManagedIps . begin ( ) ) ; ip ! = newManagedIps . end ( ) ; + + ip ) {
2023-03-07 21:50:34 +00:00
# ifdef __APPLE__
// We can't add multiple addresses to an interface on macOs unless we futz with the netmask.
// see `man ifconfig`, alias section
// "If the address is on the same subnet as the first network address for this interface, a non-conflicting netmask must be given. Usually 0xffffffff is most appropriate."
auto same_subnet = [ ip ] ( InetAddress i ) {
return ip - > network ( ) = = i . network ( ) ;
} ;
2023-03-10 15:57:54 +00:00
# endif
2023-03-07 21:50:34 +00:00
2021-11-18 20:39:55 +00:00
if ( std : : find ( n . managedIps ( ) . begin ( ) , n . managedIps ( ) . end ( ) , * ip ) = = n . managedIps ( ) . end ( ) ) {
2023-03-10 15:57:54 +00:00
# ifdef __APPLE__
2023-03-07 21:50:34 +00:00
// if same subnet as a previously added address
if (
std : : find_if ( n . managedIps ( ) . begin ( ) , n . managedIps ( ) . end ( ) , same_subnet ) ! = n . managedIps ( ) . end ( ) | |
std : : find_if ( newManagedIps2 . begin ( ) , newManagedIps2 . end ( ) , same_subnet ) ! = newManagedIps2 . end ( )
) {
if ( ip - > isV4 ( ) ) {
ip - > setPort ( 32 ) ;
} else {
ip - > setPort ( 128 ) ;
}
} else {
newManagedIps2 . push_back ( * ip ) ;
}
# endif
2023-03-10 15:57:54 +00:00
if ( ! n . tap ( ) - > addIp ( * ip ) ) {
fprintf ( stderr , " ERROR: unable to add ip address %s " ZT_EOL_S , ip - > toString ( ipbuf ) ) ;
}
else {
# ifdef __WINDOWS__
WinFWHelper : : newICMPRule ( * ip , n . config ( ) . nwid ) ;
# endif
}
}
2016-07-12 16:43:12 +00:00
}
2021-11-05 15:02:10 +00:00
# ifdef __APPLE__
2021-12-15 22:36:50 +00:00
if ( ! MacDNSHelper : : addIps ( n . config ( ) . nwid , n . config ( ) . mac , n . tap ( ) - > deviceName ( ) . c_str ( ) , newManagedIps ) )
2021-11-05 15:02:10 +00:00
fprintf ( stderr , " ERROR: unable to add v6 addresses to system configuration " ZT_EOL_S ) ;
2017-02-22 01:55:00 +00:00
# endif
2021-11-18 20:39:55 +00:00
n . setManagedIps ( newManagedIps ) ;
2016-06-17 20:14:48 +00:00
}
if ( syncRoutes ) {
2020-11-03 00:02:07 +00:00
// Get tap device name (use LUID in hex on Windows) and IP addresses.
2018-02-08 22:15:32 +00:00
# if defined(__WINDOWS__) && !defined(ZT_SDK)
2020-11-03 00:09:11 +00:00
char tapdevbuf [ 64 ] ;
2021-11-18 21:36:09 +00:00
OSUtils : : ztsnprintf ( tapdevbuf , sizeof ( tapdevbuf ) , " %.16llx " , ( unsigned long long ) ( ( WindowsEthernetTap * ) ( n . tap ( ) . get ( ) ) ) - > luid ( ) . Value ) ;
2020-11-13 21:02:59 +00:00
std : : string tapdev ( tapdevbuf ) ;
2016-06-21 20:54:03 +00:00
# else
2021-11-18 20:39:55 +00:00
std : : string tapdev ( n . tap ( ) - > deviceName ( ) ) ;
2016-06-21 20:54:03 +00:00
# endif
2016-07-12 15:42:36 +00:00
2021-11-18 20:39:55 +00:00
std : : vector < InetAddress > tapIps ( n . tap ( ) - > ips ( ) ) ;
2020-11-13 21:02:59 +00:00
std : : set < InetAddress > myIps ( tapIps . begin ( ) , tapIps . end ( ) ) ;
2021-11-18 20:39:55 +00:00
for ( unsigned int i = 0 ; i < n . config ( ) . assignedAddressCount ; + + i )
myIps . insert ( InetAddress ( n . config ( ) . assignedAddresses [ i ] ) ) ;
2020-11-13 21:02:59 +00:00
2020-11-03 00:02:07 +00:00
std : : set < InetAddress > haveRouteTargets ;
2021-11-18 20:39:55 +00:00
for ( unsigned int i = 0 ; i < n . config ( ) . routeCount ; + + i ) {
const InetAddress * const target = reinterpret_cast < const InetAddress * > ( & ( n . config ( ) . routes [ i ] . target ) ) ;
const InetAddress * const via = reinterpret_cast < const InetAddress * > ( & ( n . config ( ) . routes [ i ] . via ) ) ;
2020-11-03 00:02:07 +00:00
2020-11-13 23:16:14 +00:00
// Make sure we are allowed to set this managed route, and that 'via' is not our IP. The latter
// avoids setting routes via the router on the router.
2020-11-06 16:01:45 +00:00
if ( ( ! checkIfManagedIsAllowed ( n , * target ) ) | | ( ( via - > ss_family = = target - > ss_family ) & & ( matchIpOnly ( myIps , * via ) ) ) )
continue ;
// Find an IP on the interface that can be a source IP, abort if no IPs assigned.
2020-11-13 23:16:14 +00:00
const InetAddress * src = nullptr ;
2020-11-06 16:01:45 +00:00
unsigned int mostMatchingPrefixBits = 0 ;
2020-11-13 21:02:59 +00:00
for ( std : : set < InetAddress > : : const_iterator i ( myIps . begin ( ) ) ; i ! = myIps . end ( ) ; + + i ) {
2020-11-06 16:01:45 +00:00
const unsigned int matchingPrefixBits = i - > matchingPrefixBits ( * target ) ;
Don't use v6 source addresses for v4 routes
and vice versa.
For issue #1104
With some printf debugging, I was seeing:
here, src fe80::3c7a:2dff:fe0c:21ed, target 10.147.20.0, matchingPrefixBits 0, mostMatchingPrefixBits 0
here, src fd8b:d512:4fd6:255:3c99:932f:2fda:6eff, target 10.147.20.0, matchingPrefixBits 0, mostMatchingPrefixBits 0
and (matchingPrefixBits >= mostMatchingPrefixBits) would be true
Then on mac, somewhere downstream from there, the default route would
get messed up:
default via 92:29:f1:6f:2f:76 dev en0
2021-08-03 22:58:58 +00:00
if ( matchingPrefixBits > = mostMatchingPrefixBits & & ( ( target - > isV4 ( ) & & i - > isV4 ( ) ) | | ( target - > isV6 ( ) & & i - > isV6 ( ) ) ) ) {
2020-11-06 16:01:45 +00:00
mostMatchingPrefixBits = matchingPrefixBits ;
src = & ( * i ) ;
2020-11-03 00:02:07 +00:00
}
}
if ( ! src )
continue ;
2020-11-13 23:16:14 +00:00
// Ignore routes implied by local managed IPs since adding the IP adds the route.
// Apple on the other hand seems to need this at least on some versions.
# ifndef __APPLE__
bool haveRoute = false ;
2021-11-30 23:22:31 +00:00
for ( std : : vector < InetAddress > : : iterator ip ( n . managedIps ( ) . begin ( ) ) ; ip ! = n . managedIps ( ) . end ( ) ; + + ip ) {
2020-11-13 23:16:14 +00:00
if ( ( target - > netmaskBits ( ) = = ip - > netmaskBits ( ) ) & & ( target - > containsAddress ( * ip ) ) ) {
haveRoute = true ;
break ;
}
}
if ( haveRoute )
continue ;
# endif
2020-11-03 00:02:07 +00:00
haveRouteTargets . insert ( * target ) ;
# ifndef ZT_SDK
2021-11-18 20:39:55 +00:00
SharedPtr < ManagedRoute > & mr = n . managedRoutes ( ) [ * target ] ;
2020-11-03 00:02:07 +00:00
if ( ! mr )
mr . set ( new ManagedRoute ( * target , * via , * src , tapdev . c_str ( ) ) ) ;
# endif
}
2021-11-18 20:39:55 +00:00
for ( std : : map < InetAddress , SharedPtr < ManagedRoute > > : : iterator r ( n . managedRoutes ( ) . begin ( ) ) ; r ! = n . managedRoutes ( ) . end ( ) ; ) {
2020-11-03 00:02:07 +00:00
if ( haveRouteTargets . find ( r - > first ) = = haveRouteTargets . end ( ) )
2021-11-18 20:39:55 +00:00
n . managedRoutes ( ) . erase ( r + + ) ;
2020-11-03 00:02:07 +00:00
else + + r ;
}
2020-11-14 00:07:54 +00:00
// Sync device-local managed routes first, then indirect results. That way
// we don't get destination unreachable for routes that are via things
// that do not yet have routes in the system.
2021-11-18 20:39:55 +00:00
for ( std : : map < InetAddress , SharedPtr < ManagedRoute > > : : iterator r ( n . managedRoutes ( ) . begin ( ) ) ; r ! = n . managedRoutes ( ) . end ( ) ; + + r ) {
2020-11-14 00:07:54 +00:00
if ( ! r - > second - > via ( ) )
2020-11-14 02:21:28 +00:00
r - > second - > sync ( ) ;
2020-11-14 00:07:54 +00:00
}
2021-11-18 20:39:55 +00:00
for ( std : : map < InetAddress , SharedPtr < ManagedRoute > > : : iterator r ( n . managedRoutes ( ) . begin ( ) ) ; r ! = n . managedRoutes ( ) . end ( ) ; + + r ) {
2020-11-14 00:07:54 +00:00
if ( r - > second - > via ( ) )
2020-11-14 02:21:28 +00:00
r - > second - > sync ( ) ;
2020-11-14 00:07:54 +00:00
}
2016-06-17 20:14:48 +00:00
}
2020-07-31 18:42:03 +00:00
if ( syncDns ) {
2021-11-18 20:39:55 +00:00
if ( n . allowDNS ( ) ) {
if ( strlen ( n . config ( ) . dns . domain ) ! = 0 ) {
2020-09-10 22:59:18 +00:00
std : : vector < InetAddress > servers ;
for ( int j = 0 ; j < ZT_MAX_DNS_SERVERS ; + + j ) {
2021-11-18 20:39:55 +00:00
InetAddress a ( n . config ( ) . dns . server_addr [ j ] ) ;
2020-09-10 22:59:18 +00:00
if ( a . isV4 ( ) | | a . isV6 ( ) ) {
servers . push_back ( a ) ;
}
2020-07-31 18:42:03 +00:00
}
2021-11-18 20:39:55 +00:00
n . tap ( ) - > setDns ( n . config ( ) . dns . domain , servers ) ;
2020-07-31 18:42:03 +00:00
}
2020-09-10 22:59:18 +00:00
} else {
# ifdef __APPLE__
2021-11-18 20:39:55 +00:00
MacDNSHelper : : removeDNS ( n . config ( ) . nwid ) ;
2020-09-10 22:59:18 +00:00
# elif defined(__WINDOWS__)
2021-11-18 20:39:55 +00:00
WinDNSHelper : : removeDNS ( n . config ( ) . nwid ) ;
2020-09-10 22:59:18 +00:00
# endif
2020-07-31 18:42:03 +00:00
}
2020-09-10 22:59:18 +00:00
2020-07-31 18:42:03 +00:00
}
2016-06-17 20:14:48 +00:00
}
2017-03-07 21:53:11 +00:00
// =========================================================================
// Handlers for Node and Phy<> callbacks
// =========================================================================
2016-11-22 18:54:58 +00:00
2016-04-05 22:44:08 +00:00
inline void phyOnDatagram ( PhySocket * sock , void * * uptr , const struct sockaddr * localAddr , const struct sockaddr * from , void * data , unsigned long len )
2015-04-10 01:14:27 +00:00
{
2023-01-11 00:01:07 +00:00
if ( _forceTcpRelay ) {
return ;
}
2023-04-21 19:12:43 +00:00
Metrics : : udp_recv + = len ;
2018-11-13 18:19:51 +00:00
const uint64_t now = OSUtils : : now ( ) ;
2023-04-21 19:12:43 +00:00
if ( ( len > = 16 ) & & ( reinterpret_cast < const InetAddress * > ( from ) - > ipScope ( ) = = InetAddress : : IP_SCOPE_GLOBAL ) ) {
2018-11-13 18:19:51 +00:00
_lastDirectReceiveFromGlobal = now ;
2023-04-21 19:12:43 +00:00
}
2019-06-19 17:19:59 +00:00
const ZT_ResultCode rc = _node - > processWirePacket ( nullptr , now , reinterpret_cast < int64_t > ( sock ) , reinterpret_cast < const struct sockaddr_storage * > ( from ) , data , len , & _nextBackgroundTaskDeadline ) ;
if ( ZT_ResultCode_isFatal ( rc ) ) {
char tmp [ 256 ] ;
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " fatal error code from processWirePacket: %d " , ( int ) rc ) ;
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = tmp ;
this - > terminate ( ) ;
2018-11-12 06:35:15 +00:00
}
2015-04-10 01:14:27 +00:00
}
2015-04-11 00:07:06 +00:00
inline void phyOnTcpConnect ( PhySocket * sock , void * * uptr , bool success )
2015-04-10 01:14:27 +00:00
{
2017-06-05 19:15:28 +00:00
if ( ! success ) {
phyOnTcpClose ( sock , uptr ) ;
2015-04-28 19:43:10 +00:00
return ;
2017-06-05 19:15:28 +00:00
}
2015-04-28 19:43:10 +00:00
2017-06-05 19:15:28 +00:00
TcpConnection * const tc = reinterpret_cast < TcpConnection * > ( * uptr ) ;
if ( ! tc ) { // sanity check
_phy . close ( sock , true ) ;
return ;
}
2015-04-28 19:43:10 +00:00
tc - > sock = sock ;
2017-06-05 19:15:28 +00:00
if ( tc - > type = = TcpConnection : : TCP_TUNNEL_OUTGOING ) {
if ( _tcpFallbackTunnel )
_phy . close ( _tcpFallbackTunnel - > sock ) ;
_tcpFallbackTunnel = tc ;
_phy . streamSend ( sock , ZT_TCP_TUNNEL_HELLO , sizeof ( ZT_TCP_TUNNEL_HELLO ) ) ;
} else {
_phy . close ( sock , true ) ;
}
2015-04-10 01:14:27 +00:00
}
2015-04-11 00:07:06 +00:00
inline void phyOnTcpAccept ( PhySocket * sockL , PhySocket * sockN , void * * uptrL , void * * uptrN , const struct sockaddr * from )
2015-04-10 01:14:27 +00:00
{
2016-11-14 23:29:36 +00:00
if ( ! from ) {
2016-04-05 22:44:08 +00:00
_phy . close ( sockN , false ) ;
return ;
} else {
2019-01-14 19:34:46 +00:00
# ifdef ZT_SDK
// Immediately close new local connections. The intention is to prevent the backplane from being accessed when operating as libzt
if ( ! allowHttpBackplaneManagement & & ( ( InetAddress * ) from ) - > ipScope ( ) = = InetAddress : : IP_SCOPE_LOOPBACK ) {
_phy . close ( sockN , false ) ;
return ;
}
# endif
2016-04-05 22:44:08 +00:00
TcpConnection * tc = new TcpConnection ( ) ;
2017-06-05 19:15:28 +00:00
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
_tcpConnections . push_back ( tc ) ;
}
tc - > type = TcpConnection : : TCP_UNCATEGORIZED_INCOMING ;
2016-04-05 22:44:08 +00:00
tc - > parent = this ;
tc - > sock = sockN ;
2017-06-06 23:11:19 +00:00
tc - > remoteAddr = from ;
2017-06-05 19:15:28 +00:00
tc - > lastReceive = OSUtils : : now ( ) ;
2016-04-05 22:44:08 +00:00
http_parser_init ( & ( tc - > parser ) , HTTP_REQUEST ) ;
tc - > parser . data = ( void * ) tc ;
tc - > messageSize = 0 ;
2017-06-05 19:15:28 +00:00
2016-04-05 22:44:08 +00:00
* uptrN = ( void * ) tc ;
}
2015-04-10 01:14:27 +00:00
}
2017-06-05 19:15:28 +00:00
void phyOnTcpClose ( PhySocket * sock , void * * uptr )
2015-04-10 01:14:27 +00:00
{
2015-05-22 22:46:06 +00:00
TcpConnection * tc = ( TcpConnection * ) * uptr ;
if ( tc ) {
2017-06-05 19:15:28 +00:00
if ( tc = = _tcpFallbackTunnel ) {
2015-05-22 01:33:52 +00:00
_tcpFallbackTunnel = ( TcpConnection * ) 0 ;
2017-06-05 19:15:28 +00:00
}
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
_tcpConnections . erase ( std : : remove ( _tcpConnections . begin ( ) , _tcpConnections . end ( ) , tc ) , _tcpConnections . end ( ) ) ;
}
2015-05-22 22:46:06 +00:00
delete tc ;
2015-05-22 01:33:52 +00:00
}
2015-04-10 01:14:27 +00:00
}
2017-06-05 19:15:28 +00:00
void phyOnTcpData ( PhySocket * sock , void * * uptr , void * data , unsigned long len )
2015-04-10 01:14:27 +00:00
{
2017-06-05 19:15:28 +00:00
try {
if ( ! len ) return ; // sanity check, should never happen
2023-04-21 19:12:43 +00:00
Metrics : : tcp_recv + = len ;
2017-06-05 19:15:28 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( * uptr ) ;
tc - > lastReceive = OSUtils : : now ( ) ;
switch ( tc - > type ) {
2023-04-28 18:03:28 +00:00
// TODO: Remove Me
// case TcpConnection::TCP_UNCATEGORIZED_INCOMING:
// switch(reinterpret_cast<uint8_t *>(data)[0]) {
// // HTTP: GET, PUT, POST, HEAD, DELETE
// case 'G':
// case 'P':
// case 'D':
// case 'H': {
// // This is only allowed from IPs permitted to access the management
// // backplane, which is just 127.0.0.1/::1 unless otherwise configured.
// bool allow;
// {
// Mutex::Lock _l(_localConfig_m);
// if (_allowManagementFrom.empty()) {
// allow = (tc->remoteAddr.ipScope() == InetAddress::IP_SCOPE_LOOPBACK);
// } else {
// allow = false;
// for(std::vector<InetAddress>::const_iterator i(_allowManagementFrom.begin());i!=_allowManagementFrom.end();++i) {
// if (i->containsAddress(tc->remoteAddr)) {
// allow = true;
// break;
// }
// }
// }
// }
// if (allow) {
// tc->type = TcpConnection::TCP_HTTP_INCOMING;
// phyOnTcpData(sock,uptr,data,len);
// } else {
// _phy.close(sock);
// }
// } break;
// // Drop unknown protocols
// default:
// _phy.close(sock);
// break;
// }
// return;
2015-05-21 22:22:41 +00:00
2017-06-05 19:15:28 +00:00
case TcpConnection : : TCP_HTTP_INCOMING :
case TcpConnection : : TCP_HTTP_OUTGOING :
http_parser_execute ( & ( tc - > parser ) , & HTTP_PARSER_SETTINGS , ( const char * ) data , len ) ;
if ( ( tc - > parser . upgrade ) | | ( tc - > parser . http_errno ! = HPE_OK ) )
_phy . close ( sock ) ;
2015-04-28 19:43:10 +00:00
return ;
2015-05-21 22:22:41 +00:00
2017-06-05 19:15:28 +00:00
case TcpConnection : : TCP_TUNNEL_OUTGOING :
tc - > readq . append ( ( const char * ) data , len ) ;
while ( tc - > readq . length ( ) > = 5 ) {
const char * data = tc - > readq . data ( ) ;
const unsigned long mlen = ( ( ( ( ( unsigned long ) data [ 3 ] ) & 0xff ) < < 8 ) | ( ( ( unsigned long ) data [ 4 ] ) & 0xff ) ) ;
if ( tc - > readq . length ( ) > = ( mlen + 5 ) ) {
InetAddress from ;
2015-04-28 19:43:10 +00:00
unsigned long plen = mlen ; // payload length, modified if there's an IP header
2017-06-05 19:15:28 +00:00
data + = 5 ; // skip forward past pseudo-TLS junk and mlen
if ( plen = = 4 ) {
// Hello message, which isn't sent by proxy and would be ignored by client
} else if ( plen ) {
// Messages should contain IPv4 or IPv6 source IP address data
switch ( data [ 0 ] ) {
case 4 : // IPv4
if ( plen > = 7 ) {
from . set ( ( const void * ) ( data + 1 ) , 4 , ( ( ( ( unsigned int ) data [ 5 ] ) & 0xff ) < < 8 ) | ( ( ( unsigned int ) data [ 6 ] ) & 0xff ) ) ;
data + = 7 ; // type + 4 byte IP + 2 byte port
plen - = 7 ;
} else {
_phy . close ( sock ) ;
return ;
}
break ;
case 6 : // IPv6
if ( plen > = 19 ) {
from . set ( ( const void * ) ( data + 1 ) , 16 , ( ( ( ( unsigned int ) data [ 17 ] ) & 0xff ) < < 8 ) | ( ( ( unsigned int ) data [ 18 ] ) & 0xff ) ) ;
data + = 19 ; // type + 16 byte IP + 2 byte port
plen - = 19 ;
} else {
_phy . close ( sock ) ;
return ;
}
break ;
case 0 : // none/omitted
+ + data ;
- - plen ;
break ;
default : // invalid address type
2015-04-30 17:47:27 +00:00
_phy . close ( sock ) ;
return ;
2017-06-05 19:15:28 +00:00
}
if ( from ) {
InetAddress fakeTcpLocalInterfaceAddress ( ( uint32_t ) 0xffffffff , 0xffff ) ;
const ZT_ResultCode rc = _node - > processWirePacket (
( void * ) 0 ,
OSUtils : : now ( ) ,
2017-07-06 18:45:22 +00:00
- 1 ,
2017-06-05 19:15:28 +00:00
reinterpret_cast < struct sockaddr_storage * > ( & from ) ,
data ,
plen ,
& _nextBackgroundTaskDeadline ) ;
if ( ZT_ResultCode_isFatal ( rc ) ) {
char tmp [ 256 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( tmp , sizeof ( tmp ) , " fatal error code from processWirePacket: %d " , ( int ) rc ) ;
2017-06-05 19:15:28 +00:00
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = tmp ;
this - > terminate ( ) ;
2015-04-30 17:47:27 +00:00
_phy . close ( sock ) ;
return ;
2015-04-28 19:43:10 +00:00
}
2015-05-22 01:33:52 +00:00
}
2015-04-28 19:43:10 +00:00
}
2015-05-21 22:22:41 +00:00
2017-06-05 19:15:28 +00:00
if ( tc - > readq . length ( ) > ( mlen + 5 ) )
tc - > readq . erase ( tc - > readq . begin ( ) , tc - > readq . begin ( ) + ( mlen + 5 ) ) ;
else tc - > readq . clear ( ) ;
} else break ;
}
return ;
2015-05-21 22:22:41 +00:00
2017-06-05 19:15:28 +00:00
}
} catch ( . . . ) {
_phy . close ( sock ) ;
2015-04-28 19:43:10 +00:00
}
2015-04-10 01:14:27 +00:00
}
2015-04-11 00:07:06 +00:00
inline void phyOnTcpWritable ( PhySocket * sock , void * * uptr )
2015-04-10 01:14:27 +00:00
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( * uptr ) ;
2017-06-05 19:15:28 +00:00
bool closeit = false ;
{
Mutex : : Lock _l ( tc - > writeq_m ) ;
if ( tc - > writeq . length ( ) > 0 ) {
long sent = ( long ) _phy . streamSend ( sock , tc - > writeq . data ( ) , ( unsigned long ) tc - > writeq . length ( ) , true ) ;
2023-04-21 19:12:43 +00:00
Metrics : : tcp_send + = sent ;
2017-06-05 19:15:28 +00:00
if ( sent > 0 ) {
if ( ( unsigned long ) sent > = ( unsigned long ) tc - > writeq . length ( ) ) {
tc - > writeq . clear ( ) ;
_phy . setNotifyWritable ( sock , false ) ;
if ( tc - > type = = TcpConnection : : TCP_HTTP_INCOMING )
closeit = true ; // HTTP keep alive not supported
} else {
tc - > writeq . erase ( tc - > writeq . begin ( ) , tc - > writeq . begin ( ) + sent ) ;
}
2015-05-22 21:52:23 +00:00
}
2017-06-05 19:15:28 +00:00
} else {
_phy . setNotifyWritable ( sock , false ) ;
2015-04-11 02:08:49 +00:00
}
2015-05-22 21:52:23 +00:00
}
2017-06-05 19:15:28 +00:00
if ( closeit )
_phy . close ( sock ) ;
2015-04-10 01:14:27 +00:00
}
2015-12-22 00:15:39 +00:00
inline void phyOnFileDescriptorActivity ( PhySocket * sock , void * * uptr , bool readable , bool writable ) { }
2015-09-02 21:32:01 +00:00
inline void phyOnUnixAccept ( PhySocket * sockL , PhySocket * sockN , void * * uptrL , void * * uptrN ) { }
inline void phyOnUnixClose ( PhySocket * sock , void * * uptr ) { }
inline void phyOnUnixData ( PhySocket * sock , void * * uptr , void * data , unsigned long len ) { }
2018-08-09 18:39:42 +00:00
inline void phyOnUnixWritable ( PhySocket * sock , void * * uptr ) { }
2015-09-02 21:32:01 +00:00
2016-01-12 19:34:22 +00:00
inline int nodeVirtualNetworkConfigFunction ( uint64_t nwid , void * * nuptr , enum ZT_VirtualNetworkConfigOperation op , const ZT_VirtualNetworkConfig * nwc )
2015-04-10 01:14:27 +00:00
{
2016-06-14 17:09:26 +00:00
Mutex : : Lock _l ( _nets_m ) ;
NetworkState & n = _nets [ nwid ] ;
2021-11-29 22:11:29 +00:00
n . setWebPort ( _primaryPort ) ;
2016-06-14 17:09:26 +00:00
2021-11-29 22:11:29 +00:00
switch ( op ) {
2015-09-24 23:21:36 +00:00
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP :
2021-11-18 20:39:55 +00:00
if ( ! n . tap ( ) ) {
2015-04-15 00:57:51 +00:00
try {
2016-06-14 17:09:26 +00:00
char friendlyName [ 128 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( friendlyName , sizeof ( friendlyName ) , " ZeroTier One [%.16llx] " , nwid ) ;
2017-03-25 00:00:14 +00:00
2021-11-18 20:39:55 +00:00
n . setTap ( EthernetTap : : newInstance (
2019-08-07 23:20:17 +00:00
nullptr ,
2015-04-15 00:57:51 +00:00
_homePath . c_str ( ) ,
MAC ( nwc - > mac ) ,
nwc - > mtu ,
2015-04-24 22:05:28 +00:00
( unsigned int ) ZT_IF_METRIC ,
2015-04-15 00:57:51 +00:00
nwid ,
friendlyName ,
StapFrameHandler ,
2021-11-18 20:39:55 +00:00
( void * ) this ) ) ;
2016-06-14 17:09:26 +00:00
* nuptr = ( void * ) & n ;
2016-06-21 23:52:49 +00:00
char nlcpath [ 256 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( nlcpath , sizeof ( nlcpath ) , " %s " ZT_PATH_SEPARATOR_S " networks.d " ZT_PATH_SEPARATOR_S " %.16llx.local.conf " , _homePath . c_str ( ) , nwid ) ;
2016-06-21 23:52:49 +00:00
std : : string nlcbuf ;
if ( OSUtils : : readFile ( nlcpath , nlcbuf ) ) {
Dictionary < 4096 > nc ;
nc . load ( nlcbuf . c_str ( ) ) ;
2017-01-22 22:02:34 +00:00
Buffer < 1024 > allowManaged ;
2021-05-04 02:35:28 +00:00
if ( nc . get ( " allowManaged " , allowManaged ) & & allowManaged . size ( ) > 0 ) {
2017-01-22 22:02:34 +00:00
std : : string addresses ( allowManaged . begin ( ) , allowManaged . size ( ) ) ;
if ( allowManaged . size ( ) < = 5 ) { // untidy parsing for backward compatibility
if ( allowManaged [ 0 ] = = ' 1 ' | | allowManaged [ 0 ] = = ' t ' | | allowManaged [ 0 ] = = ' T ' ) {
2021-11-18 20:39:55 +00:00
n . setAllowManaged ( true ) ;
2017-01-22 22:02:34 +00:00
} else {
2021-11-18 20:39:55 +00:00
n . setAllowManaged ( false ) ;
2017-01-22 22:02:34 +00:00
}
} else {
// this should be a list of IP addresses
2021-11-18 20:39:55 +00:00
n . setAllowManaged ( true ) ;
2017-01-22 22:02:34 +00:00
size_t pos = 0 ;
while ( true ) {
size_t nextPos = addresses . find ( ' , ' , pos ) ;
std : : string address = addresses . substr ( pos , ( nextPos = = std : : string : : npos ? addresses . size ( ) : nextPos ) - pos ) ;
2021-11-18 20:39:55 +00:00
n . addToAllowManagedWhiteList ( InetAddress ( address . c_str ( ) ) ) ;
2017-01-22 22:02:34 +00:00
if ( nextPos = = std : : string : : npos ) break ;
pos = nextPos + 1 ;
}
}
} else {
2021-11-18 20:39:55 +00:00
n . setAllowManaged ( true ) ;
2017-01-22 22:02:34 +00:00
}
2021-11-18 20:39:55 +00:00
n . setAllowGlobal ( nc . getB ( " allowGlobal " , false ) ) ;
n . setAllowDefault ( nc . getB ( " allowDefault " , false ) ) ;
n . setAllowDNS ( nc . getB ( " allowDNS " , false ) ) ;
2016-06-21 23:52:49 +00:00
}
2015-07-31 00:00:57 +00:00
} catch ( std : : exception & exc ) {
# ifdef __WINDOWS__
FILE * tapFailLog = fopen ( ( _homePath + ZT_PATH_SEPARATOR_S " port_error_log.txt " ) . c_str ( ) , " a " ) ;
if ( tapFailLog ) {
2016-08-16 21:07:11 +00:00
fprintf ( tapFailLog , " %.16llx: %s " ZT_EOL_S , ( unsigned long long ) nwid , exc . what ( ) ) ;
2015-07-31 00:00:57 +00:00
fclose ( tapFailLog ) ;
}
# else
2016-08-16 21:07:11 +00:00
fprintf ( stderr , " ERROR: unable to configure virtual network port: %s " ZT_EOL_S , exc . what ( ) ) ;
2015-07-31 00:00:57 +00:00
# endif
2016-06-14 17:09:26 +00:00
_nets . erase ( nwid ) ;
2015-07-31 00:00:57 +00:00
return - 999 ;
2015-04-15 00:57:51 +00:00
} catch ( . . . ) {
2015-04-15 20:09:20 +00:00
return - 999 ; // tap init failed
2015-04-15 00:57:51 +00:00
}
}
2016-06-14 17:09:26 +00:00
// After setting up tap, fall through to CONFIG_UPDATE since we also want to do this...
2015-04-15 00:57:51 +00:00
2016-06-14 17:09:26 +00:00
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE :
2021-11-18 20:39:55 +00:00
n . setConfig ( nwc ) ;
2021-12-01 20:07:05 +00:00
2021-11-18 20:39:55 +00:00
if ( n . tap ( ) ) { // sanity check
2018-02-08 22:15:32 +00:00
# if defined(__WINDOWS__) && !defined(ZT_SDK)
2017-05-05 03:10:49 +00:00
// wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized
2018-05-07 19:51:39 +00:00
//
2017-05-05 03:10:49 +00:00
// without WindowsEthernetTap::isInitialized() returning true, the won't actually
// be online yet and setting managed routes on it will fail.
const int MAX_SLEEP_COUNT = 500 ;
2021-11-18 21:36:09 +00:00
for ( int i = 0 ; ! ( ( WindowsEthernetTap * ) ( n . tap ( ) . get ( ) ) ) - > isInitialized ( ) & & i < MAX_SLEEP_COUNT ; i + + ) {
2017-05-05 03:10:49 +00:00
Sleep ( 10 ) ;
}
2017-01-05 19:43:26 +00:00
# endif
2020-07-31 18:42:03 +00:00
syncManagedStuff ( n , true , true , true ) ;
2021-11-18 20:39:55 +00:00
n . tap ( ) - > setMtu ( nwc - > mtu ) ;
2015-04-15 20:09:20 +00:00
} else {
2016-06-14 17:09:26 +00:00
_nets . erase ( nwid ) ;
2015-04-15 20:09:20 +00:00
return - 999 ; // tap init failed
2015-04-15 00:57:51 +00:00
}
break ;
2016-06-14 17:09:26 +00:00
2015-09-24 23:21:36 +00:00
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN :
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY :
2021-11-18 20:39:55 +00:00
if ( n . tap ( ) ) { // sanity check
2018-02-08 22:15:32 +00:00
# if defined(__WINDOWS__) && !defined(ZT_SDK)
2021-11-18 21:36:09 +00:00
std : : string winInstanceId ( ( ( WindowsEthernetTap * ) ( n . tap ( ) . get ( ) ) ) - > instanceId ( ) ) ;
2015-04-24 23:31:19 +00:00
# endif
2016-01-12 19:34:22 +00:00
* nuptr = ( void * ) 0 ;
2021-11-18 20:39:55 +00:00
n . tap ( ) . reset ( ) ;
2016-06-14 17:09:26 +00:00
_nets . erase ( nwid ) ;
2017-10-10 22:01:15 +00:00
# if defined(__WINDOWS__) && !defined(ZT_SDK)
2022-12-19 21:26:29 +00:00
if ( ( op = = ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY ) & & ( winInstanceId . length ( ) > 0 ) ) {
2015-07-30 18:31:38 +00:00
WindowsEthernetTap : : deletePersistentTapDevice ( winInstanceId . c_str ( ) ) ;
2022-12-19 21:26:29 +00:00
WinFWHelper : : removeICMPRules ( nwid ) ;
}
2015-04-24 23:31:19 +00:00
# endif
2016-06-21 23:52:49 +00:00
if ( op = = ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY ) {
char nlcpath [ 256 ] ;
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( nlcpath , sizeof ( nlcpath ) , " %s " ZT_PATH_SEPARATOR_S " networks.d " ZT_PATH_SEPARATOR_S " %.16llx.local.conf " , _homePath . c_str ( ) , nwid ) ;
2016-06-21 23:52:49 +00:00
OSUtils : : rm ( nlcpath ) ;
}
2016-06-14 17:09:26 +00:00
} else {
_nets . erase ( nwid ) ;
2015-04-15 00:57:51 +00:00
}
break ;
}
2015-04-10 03:54:00 +00:00
return 0 ;
2015-04-10 01:14:27 +00:00
}
2015-09-24 23:21:36 +00:00
inline void nodeEventCallback ( enum ZT_Event event , const void * metaData )
2015-04-10 01:14:27 +00:00
{
switch ( event ) {
2015-09-24 23:21:36 +00:00
case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION : {
2015-04-10 01:22:04 +00:00
Mutex : : Lock _l ( _termReason_m ) ;
2015-04-10 01:14:27 +00:00
_termReason = ONE_IDENTITY_COLLISION ;
_fatalErrorMessage = " identity/address collision " ;
this - > terminate ( ) ;
} break ;
2015-09-24 23:21:36 +00:00
case ZT_EVENT_TRACE : {
2015-04-10 01:14:27 +00:00
if ( metaData ) {
2016-08-16 21:07:11 +00:00
: : fprintf ( stderr , " %s " ZT_EOL_S , ( const char * ) metaData ) ;
2015-04-10 01:14:27 +00:00
: : fflush ( stderr ) ;
}
} break ;
2017-01-12 01:20:43 +00:00
case ZT_EVENT_USER_MESSAGE : {
const ZT_UserMessage * um = reinterpret_cast < const ZT_UserMessage * > ( metaData ) ;
if ( ( um - > typeId = = ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE ) & & ( _updater ) ) {
_updater - > handleSoftwareUpdateUserMessage ( um - > origin , um - > data , um - > length ) ;
}
} break ;
2017-07-14 20:03:16 +00:00
case ZT_EVENT_REMOTE_TRACE : {
const ZT_RemoteTrace * rt = reinterpret_cast < const ZT_RemoteTrace * > ( metaData ) ;
if ( ( rt ) & & ( rt - > len > 0 ) & & ( rt - > len < = ZT_MAX_REMOTE_TRACE_SIZE ) & & ( rt - > data ) )
_controller - > handleRemoteTrace ( * rt ) ;
}
2015-04-10 01:14:27 +00:00
default :
break ;
}
}
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
inline bool nodeVaultPutIdentity ( enum ZT_StateObjectType type , const void * data , int len )
{
bool retval = false ;
if ( type ! = ZT_STATE_OBJECT_IDENTITY_PUBLIC & & type ! = ZT_STATE_OBJECT_IDENTITY_SECRET ) {
return retval ;
}
CURL * curl = curl_easy_init ( ) ;
if ( curl ) {
char token [ 512 ] = { 0 } ;
snprintf ( token , sizeof ( token ) , " X-Vault-Token: %s " , _vaultToken . c_str ( ) ) ;
struct curl_slist * chunk = NULL ;
chunk = curl_slist_append ( chunk , token ) ;
char content_type [ 512 ] = { 0 } ;
snprintf ( content_type , sizeof ( content_type ) , " Content-Type: application/json " ) ;
chunk = curl_slist_append ( chunk , content_type ) ;
curl_easy_setopt ( curl , CURLOPT_HTTPHEADER , chunk ) ;
char url [ 2048 ] = { 0 } ;
snprintf ( url , sizeof ( url ) , " %s/v1/%s " , _vaultURL . c_str ( ) , _vaultPath . c_str ( ) ) ;
curl_easy_setopt ( curl , CURLOPT_URL , url ) ;
json d = json : : object ( ) ;
if ( type = = ZT_STATE_OBJECT_IDENTITY_PUBLIC ) {
std : : string key ( ( const char * ) data , len ) ;
d [ " public " ] = key ;
}
else if ( type = = ZT_STATE_OBJECT_IDENTITY_SECRET ) {
std : : string key ( ( const char * ) data , len ) ;
d [ " secret " ] = key ;
}
if ( ! d . empty ( ) ) {
std : : string post = d . dump ( ) ;
if ( ! post . empty ( ) ) {
curl_easy_setopt ( curl , CURLOPT_POSTFIELDS , post . c_str ( ) ) ;
curl_easy_setopt ( curl , CURLOPT_POSTFIELDSIZE , post . length ( ) ) ;
# ifndef NDEBUG
curl_easy_setopt ( curl , CURLOPT_VERBOSE , 1L ) ;
# endif
CURLcode res = curl_easy_perform ( curl ) ;
if ( res = = CURLE_OK ) {
long response_code = 0 ;
curl_easy_getinfo ( curl , CURLINFO_RESPONSE_CODE , & response_code ) ;
if ( response_code = = 200 | | response_code = = 204 ) {
retval = true ;
}
}
}
}
curl_easy_cleanup ( curl ) ;
curl = NULL ;
curl_slist_free_all ( chunk ) ;
chunk = NULL ;
}
return retval ;
}
# endif
2017-07-01 00:32:07 +00:00
inline void nodeStatePutFunction ( enum ZT_StateObjectType type , const uint64_t id [ 2 ] , const void * data , int len )
2015-04-10 01:14:27 +00:00
{
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
if ( _vaultEnabled & & ( type = = ZT_STATE_OBJECT_IDENTITY_SECRET | | type = = ZT_STATE_OBJECT_IDENTITY_PUBLIC ) ) {
if ( nodeVaultPutIdentity ( type , data , len ) ) {
// value successfully written to Vault
return ;
}
// else fallback to disk
}
# endif
2017-07-06 18:45:22 +00:00
char p [ 1024 ] ;
FILE * f ;
bool secure = false ;
2017-08-23 20:40:51 +00:00
char dirname [ 1024 ] ;
dirname [ 0 ] = 0 ;
2017-07-06 17:25:36 +00:00
2017-07-06 18:45:22 +00:00
switch ( type ) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC :
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.public " , _homePath . c_str ( ) ) ;
2017-07-06 18:45:22 +00:00
break ;
case ZT_STATE_OBJECT_IDENTITY_SECRET :
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.secret " , _homePath . c_str ( ) ) ;
2017-07-06 18:45:22 +00:00
secure = true ;
break ;
case ZT_STATE_OBJECT_PLANET :
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " planet " , _homePath . c_str ( ) ) ;
2017-07-06 18:45:22 +00:00
break ;
case ZT_STATE_OBJECT_MOON :
2017-08-23 20:40:51 +00:00
OSUtils : : ztsnprintf ( dirname , sizeof ( dirname ) , " %s " ZT_PATH_SEPARATOR_S " moons.d " , _homePath . c_str ( ) ) ;
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " %.16llx.moon " , dirname , ( unsigned long long ) id [ 0 ] ) ;
2017-07-06 18:45:22 +00:00
break ;
case ZT_STATE_OBJECT_NETWORK_CONFIG :
2017-08-23 20:40:51 +00:00
OSUtils : : ztsnprintf ( dirname , sizeof ( dirname ) , " %s " ZT_PATH_SEPARATOR_S " networks.d " , _homePath . c_str ( ) ) ;
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " %.16llx.conf " , dirname , ( unsigned long long ) id [ 0 ] ) ;
2017-07-06 18:45:22 +00:00
break ;
2017-08-23 20:40:51 +00:00
case ZT_STATE_OBJECT_PEER :
OSUtils : : ztsnprintf ( dirname , sizeof ( dirname ) , " %s " ZT_PATH_SEPARATOR_S " peers.d " , _homePath . c_str ( ) ) ;
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " %.10llx.peer " , dirname , ( unsigned long long ) id [ 0 ] ) ;
break ;
2017-07-06 18:45:22 +00:00
default :
return ;
2015-04-10 02:58:04 +00:00
}
2017-07-06 18:45:22 +00:00
2019-06-17 21:02:35 +00:00
if ( ( len > = 0 ) & & ( data ) ) {
2017-07-06 18:45:22 +00:00
// 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.
2018-03-16 18:27:11 +00:00
f = fopen ( p , " rb " ) ;
2017-07-06 18:45:22 +00:00
if ( f ) {
2019-06-17 22:28:02 +00:00
char * const buf = ( char * ) malloc ( len * 4 ) ;
if ( buf ) {
long l = ( long ) fread ( buf , 1 , ( size_t ) ( len * 4 ) , f ) ;
fclose ( f ) ;
if ( ( l = = ( long ) len ) & & ( memcmp ( data , buf , l ) = = 0 ) ) {
free ( buf ) ;
return ;
}
free ( buf ) ;
}
2017-07-06 17:25:36 +00:00
}
2017-07-06 18:45:22 +00:00
2018-03-16 18:27:11 +00:00
f = fopen ( p , " wb " ) ;
2017-08-23 20:40:51 +00:00
if ( ( ! f ) & & ( dirname [ 0 ] ) ) { // create subdirectory if it does not exist
OSUtils : : mkdir ( dirname ) ;
2018-03-16 18:27:11 +00:00
f = fopen ( p , " wb " ) ;
2017-08-23 20:40:51 +00:00
}
2017-07-06 18:45:22 +00:00
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 ) ;
2015-04-10 02:58:04 +00:00
}
2015-04-10 01:14:27 +00:00
}
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
inline int nodeVaultGetIdentity ( enum ZT_StateObjectType type , void * data , unsigned int maxlen )
{
if ( type ! = ZT_STATE_OBJECT_IDENTITY_SECRET & & type ! = ZT_STATE_OBJECT_IDENTITY_PUBLIC ) {
return - 1 ;
}
int ret = - 1 ;
CURL * curl = curl_easy_init ( ) ;
if ( curl ) {
char token [ 512 ] = { 0 } ;
snprintf ( token , sizeof ( token ) , " X-Vault-Token: %s " , _vaultToken . c_str ( ) ) ;
struct curl_slist * chunk = NULL ;
chunk = curl_slist_append ( chunk , token ) ;
curl_easy_setopt ( curl , CURLOPT_HTTPHEADER , chunk ) ;
char url [ 2048 ] = { 0 } ;
snprintf ( url , sizeof ( url ) , " %s/v1/%s " , _vaultURL . c_str ( ) , _vaultPath . c_str ( ) ) ;
curl_easy_setopt ( curl , CURLOPT_URL , url ) ;
std : : string response ;
std : : string res_headers ;
curl_easy_setopt ( curl , CURLOPT_WRITEFUNCTION , & curlResponseWrite ) ;
curl_easy_setopt ( curl , CURLOPT_WRITEDATA , & response ) ;
curl_easy_setopt ( curl , CURLOPT_HEADERDATA , & res_headers ) ;
# ifndef NDEBUG
curl_easy_setopt ( curl , CURLOPT_VERBOSE , 1L ) ;
# endif
CURLcode res = curl_easy_perform ( curl ) ;
if ( res = = CURLE_OK ) {
long response_code = 0 ;
curl_easy_getinfo ( curl , CURLINFO_RESPONSE_CODE , & response_code ) ;
if ( response_code = = 200 ) {
try {
json payload = json : : parse ( response ) ;
if ( ! payload [ " data " ] . is_null ( ) ) {
json & d = payload [ " data " ] ;
if ( type = = ZT_STATE_OBJECT_IDENTITY_SECRET ) {
std : : string secret = OSUtils : : jsonString ( d [ " secret " ] , " " ) ;
if ( ! secret . empty ( ) ) {
ret = ( int ) secret . length ( ) ;
memcpy ( data , secret . c_str ( ) , ret ) ;
}
}
else if ( type = = ZT_STATE_OBJECT_IDENTITY_PUBLIC ) {
std : : string pub = OSUtils : : jsonString ( d [ " public " ] , " " ) ;
if ( ! pub . empty ( ) ) {
ret = ( int ) pub . length ( ) ;
memcpy ( data , pub . c_str ( ) , ret ) ;
}
}
}
}
catch ( . . . ) {
ret = - 1 ;
}
}
}
curl_easy_cleanup ( curl ) ;
curl = NULL ;
curl_slist_free_all ( chunk ) ;
chunk = NULL ;
}
return ret ;
}
# endif
2017-07-01 00:32:07 +00:00
inline int nodeStateGetFunction ( enum ZT_StateObjectType type , const uint64_t id [ 2 ] , void * data , unsigned int maxlen )
2015-04-10 01:14:27 +00:00
{
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
if ( _vaultEnabled & & ( type = = ZT_STATE_OBJECT_IDENTITY_SECRET | | type = = ZT_STATE_OBJECT_IDENTITY_PUBLIC ) ) {
int retval = nodeVaultGetIdentity ( type , data , maxlen ) ;
if ( retval > = 0 )
return retval ;
// else continue file based lookup
}
# endif
2017-06-05 19:15:28 +00:00
char p [ 4096 ] ;
switch ( type ) {
case ZT_STATE_OBJECT_IDENTITY_PUBLIC :
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.public " , _homePath . c_str ( ) ) ;
2017-06-05 19:15:28 +00:00
break ;
case ZT_STATE_OBJECT_IDENTITY_SECRET :
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " identity.secret " , _homePath . c_str ( ) ) ;
2017-06-05 19:15:28 +00:00
break ;
case ZT_STATE_OBJECT_PLANET :
2017-07-06 23:11:11 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " planet " , _homePath . c_str ( ) ) ;
2017-06-05 19:15:28 +00:00
break ;
case ZT_STATE_OBJECT_MOON :
2018-05-07 19:51:39 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " moons.d " ZT_PATH_SEPARATOR_S " %.16llx.moon " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
2017-06-05 19:15:28 +00:00
break ;
2017-08-23 20:40:51 +00:00
case ZT_STATE_OBJECT_NETWORK_CONFIG :
2018-05-07 19:51:39 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " networks.d " ZT_PATH_SEPARATOR_S " %.16llx.conf " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
2017-08-23 20:40:51 +00:00
break ;
case ZT_STATE_OBJECT_PEER :
2017-08-23 21:09:29 +00:00
OSUtils : : ztsnprintf ( p , sizeof ( p ) , " %s " ZT_PATH_SEPARATOR_S " peers.d " ZT_PATH_SEPARATOR_S " %.10llx.peer " , _homePath . c_str ( ) , ( unsigned long long ) id [ 0 ] ) ;
2017-08-23 20:40:51 +00:00
break ;
2017-06-05 19:15:28 +00:00
default :
return - 1 ;
2015-04-10 02:58:04 +00:00
}
2018-03-16 18:27:11 +00:00
FILE * f = fopen ( p , " rb " ) ;
2017-06-05 19:15:28 +00:00
if ( f ) {
2017-06-05 20:42:43 +00:00
int n = ( int ) fread ( data , 1 , maxlen , f ) ;
2015-04-10 02:58:04 +00:00
fclose ( f ) ;
2018-08-09 21:32:26 +00:00
# if ZT_VAULT_SUPPORT
if ( _vaultEnabled & & ( type = = ZT_STATE_OBJECT_IDENTITY_SECRET | | type = = ZT_STATE_OBJECT_IDENTITY_PUBLIC ) ) {
// If we've gotten here while Vault is enabled, Vault does not know the key and it's been
// read from disk instead.
//
// We should put the value in Vault and remove the local file.
if ( nodeVaultPutIdentity ( type , data , n ) ) {
unlink ( p ) ;
}
}
# endif
2017-06-05 20:42:43 +00:00
if ( n > = 0 )
return n ;
2015-04-10 02:58:04 +00:00
}
2017-06-05 19:15:28 +00:00
return - 1 ;
2015-04-10 01:14:27 +00:00
}
2017-07-06 18:45:22 +00:00
inline int nodeWirePacketSendFunction ( const int64_t localSocket , const struct sockaddr_storage * addr , const void * data , unsigned int len , unsigned int ttl )
2015-04-10 01:14:27 +00:00
{
2015-09-24 23:21:36 +00:00
# ifdef ZT_TCP_FALLBACK_RELAY
2018-01-10 20:41:52 +00:00
if ( _allowTcpFallbackRelay ) {
if ( addr - > ss_family = = AF_INET ) {
// TCP fallback tunnel support, currently IPv4 only
if ( ( len > = 16 ) & & ( reinterpret_cast < const InetAddress * > ( addr ) - > ipScope ( ) = = InetAddress : : IP_SCOPE_GLOBAL ) ) {
// Engage TCP tunnel fallback if we haven't received anything valid from a global
// IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting
// valid direct traffic we'll stop using it and close the socket after a while.
const int64_t now = OSUtils : : now ( ) ;
2023-01-11 00:01:07 +00:00
if ( _forceTcpRelay | | ( ( ( now - _lastDirectReceiveFromGlobal ) > ZT_TCP_FALLBACK_AFTER ) & & ( ( now - _lastRestart ) > ZT_TCP_FALLBACK_AFTER ) ) ) {
2018-01-10 20:41:52 +00:00
if ( _tcpFallbackTunnel ) {
bool flushNow = false ;
{
Mutex : : Lock _l ( _tcpFallbackTunnel - > writeq_m ) ;
if ( _tcpFallbackTunnel - > writeq . size ( ) < ( 1024 * 64 ) ) {
if ( _tcpFallbackTunnel - > writeq . length ( ) = = 0 ) {
_phy . setNotifyWritable ( _tcpFallbackTunnel - > sock , true ) ;
flushNow = true ;
}
const unsigned long mlen = len + 7 ;
_tcpFallbackTunnel - > writeq . push_back ( ( char ) 0x17 ) ;
_tcpFallbackTunnel - > writeq . push_back ( ( char ) 0x03 ) ;
_tcpFallbackTunnel - > writeq . push_back ( ( char ) 0x03 ) ; // fake TLS 1.2 header
_tcpFallbackTunnel - > writeq . push_back ( ( char ) ( ( mlen > > 8 ) & 0xff ) ) ;
_tcpFallbackTunnel - > writeq . push_back ( ( char ) ( mlen & 0xff ) ) ;
_tcpFallbackTunnel - > writeq . push_back ( ( char ) 4 ) ; // IPv4
_tcpFallbackTunnel - > writeq . append ( reinterpret_cast < const char * > ( reinterpret_cast < const void * > ( & ( reinterpret_cast < const struct sockaddr_in * > ( addr ) - > sin_addr . s_addr ) ) ) , 4 ) ;
_tcpFallbackTunnel - > writeq . append ( reinterpret_cast < const char * > ( reinterpret_cast < const void * > ( & ( reinterpret_cast < const struct sockaddr_in * > ( addr ) - > sin_port ) ) ) , 2 ) ;
_tcpFallbackTunnel - > writeq . append ( ( const char * ) data , len ) ;
2017-08-18 21:54:10 +00:00
}
}
2018-01-10 20:41:52 +00:00
if ( flushNow ) {
void * tmpptr = ( void * ) _tcpFallbackTunnel ;
phyOnTcpWritable ( _tcpFallbackTunnel - > sock , & tmpptr ) ;
}
2023-01-11 00:01:07 +00:00
} else if ( _forceTcpRelay | | ( ( ( now - _lastSendToGlobalV4 ) < ZT_TCP_FALLBACK_AFTER ) & & ( ( now - _lastSendToGlobalV4 ) > ( ZT_PING_CHECK_INVERVAL / 2 ) ) ) ) {
2022-04-28 18:05:54 +00:00
const InetAddress addr ( _fallbackRelayAddress ) ;
2018-01-10 20:41:52 +00:00
TcpConnection * tc = new TcpConnection ( ) ;
{
Mutex : : Lock _l ( _tcpConnections_m ) ;
_tcpConnections . push_back ( tc ) ;
}
tc - > type = TcpConnection : : TCP_TUNNEL_OUTGOING ;
tc - > remoteAddr = addr ;
tc - > lastReceive = OSUtils : : now ( ) ;
tc - > parent = this ;
tc - > sock = ( PhySocket * ) 0 ; // set in connect handler
tc - > messageSize = 0 ;
2016-03-03 22:21:13 +00:00
bool connected = false ;
2018-01-10 20:41:52 +00:00
_phy . tcpConnect ( reinterpret_cast < const struct sockaddr * > ( & addr ) , connected , ( void * ) tc , true ) ;
2015-05-22 01:33:52 +00:00
}
}
2018-01-10 20:41:52 +00:00
_lastSendToGlobalV4 = now ;
2015-05-22 01:33:52 +00:00
}
2016-03-03 22:21:13 +00:00
}
2016-03-03 21:52:27 +00:00
}
2023-01-11 00:01:07 +00:00
if ( _forceTcpRelay ) {
// Shortcut here so that we don't emit any UDP packets
return 0 ;
}
2018-01-10 20:41:52 +00:00
# endif // ZT_TCP_FALLBACK_RELAY
2015-05-22 01:33:52 +00:00
2017-06-06 23:11:19 +00:00
// Even when relaying we still send via UDP. This way if UDP starts
// working we can instantly "fail forward" to it and stop using TCP
// proxy fallback, which is slow.
2017-07-13 22:08:57 +00:00
if ( ( localSocket ! = - 1 ) & & ( localSocket ! = 0 ) & & ( _binder . isUdpSocketValid ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) ) ) ) {
2023-04-21 19:12:43 +00:00
if ( ( ttl ) & & ( addr - > ss_family = = AF_INET ) ) {
_phy . setIp4UdpTtl ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) , ttl ) ;
}
2017-07-06 18:45:22 +00:00
const bool r = _phy . udpSend ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) , ( const struct sockaddr * ) addr , data , len ) ;
2023-04-21 19:12:43 +00:00
if ( ( ttl ) & & ( addr - > ss_family = = AF_INET ) ) {
_phy . setIp4UdpTtl ( ( PhySocket * ) ( ( uintptr_t ) localSocket ) , 255 ) ;
}
2017-07-06 18:45:22 +00:00
return ( ( r ) ? 0 : - 1 ) ;
} else {
return ( ( _binder . udpSendAll ( _phy , addr , data , len , ttl ) ) ? 0 : - 1 ) ;
2017-06-06 23:11:19 +00:00
}
2015-04-10 01:14:27 +00:00
}
2016-01-12 19:34:22 +00:00
inline void nodeVirtualNetworkFrameFunction ( uint64_t nwid , void * * nuptr , uint64_t sourceMac , uint64_t destMac , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )
2015-04-10 01:14:27 +00:00
{
2016-06-14 17:09:26 +00:00
NetworkState * n = reinterpret_cast < NetworkState * > ( * nuptr ) ;
2021-11-18 20:39:55 +00:00
if ( ( ! n ) | | ( ! n - > tap ( ) ) )
2016-01-12 19:34:22 +00:00
return ;
2021-11-18 20:39:55 +00:00
n - > tap ( ) - > put ( MAC ( sourceMac ) , MAC ( destMac ) , etherType , data , len ) ;
2015-04-15 00:57:51 +00:00
}
2017-07-06 18:45:22 +00:00
inline int nodePathCheckFunction ( uint64_t ztaddr , const int64_t localSocket , const struct sockaddr_storage * remoteAddr )
2016-01-11 18:17:44 +00:00
{
2016-11-22 18:54:58 +00:00
// Make sure we're not trying to do ZeroTier-over-ZeroTier
{
Mutex : : Lock _l ( _nets_m ) ;
for ( std : : map < uint64_t , NetworkState > : : const_iterator n ( _nets . begin ( ) ) ; n ! = _nets . end ( ) ; + + n ) {
2021-11-18 20:39:55 +00:00
if ( n - > second . tap ( ) ) {
std : : vector < InetAddress > ips ( n - > second . tap ( ) - > ips ( ) ) ;
2016-11-22 18:54:58 +00:00
for ( std : : vector < InetAddress > : : const_iterator i ( ips . begin ( ) ) ; i ! = ips . end ( ) ; + + i ) {
if ( i - > containsAddress ( * ( reinterpret_cast < const InetAddress * > ( remoteAddr ) ) ) ) {
return 0 ;
}
2016-01-11 18:17:44 +00:00
}
}
}
}
2016-12-25 21:54:27 +00:00
2016-06-21 14:32:58 +00:00
/* Note: I do not think we need to scan for overlap with managed routes
* because of the " route forking " and interface binding that we do . This
* ensures ( we hope ) that ZeroTier traffic will still take the physical
* path even if its managed routes override this for other traffic . Will
2016-11-22 22:23:13 +00:00
* revisit if we see recursion problems . */
2016-11-22 18:54:58 +00:00
// Check blacklists
const Hashtable < uint64_t , std : : vector < InetAddress > > * blh = ( const Hashtable < uint64_t , std : : vector < InetAddress > > * ) 0 ;
const std : : vector < InetAddress > * gbl = ( const std : : vector < InetAddress > * ) 0 ;
if ( remoteAddr - > ss_family = = AF_INET ) {
blh = & _v4Blacklists ;
gbl = & _globalV4Blacklist ;
} else if ( remoteAddr - > ss_family = = AF_INET6 ) {
blh = & _v6Blacklists ;
gbl = & _globalV6Blacklist ;
}
if ( blh ) {
Mutex : : Lock _l ( _localConfig_m ) ;
const std : : vector < InetAddress > * l = blh - > get ( ztaddr ) ;
if ( l ) {
for ( std : : vector < InetAddress > : : const_iterator a ( l - > begin ( ) ) ; a ! = l - > end ( ) ; + + a ) {
if ( a - > containsAddress ( * reinterpret_cast < const InetAddress * > ( remoteAddr ) ) )
return 0 ;
}
}
2018-01-09 18:16:49 +00:00
}
if ( gbl ) {
2016-11-22 18:54:58 +00:00
for ( std : : vector < InetAddress > : : const_iterator a ( gbl - > begin ( ) ) ; a ! = gbl - > end ( ) ; + + a ) {
if ( a - > containsAddress ( * reinterpret_cast < const InetAddress * > ( remoteAddr ) ) )
return 0 ;
}
}
2016-01-11 18:17:44 +00:00
return 1 ;
}
2020-11-25 19:05:36 +00:00
inline int nodePathLookupFunction ( uint64_t ztaddr , int family , struct sockaddr_storage * result )
2016-11-22 18:54:58 +00:00
{
2020-11-25 19:05:36 +00:00
const Hashtable < uint64_t , std : : vector < InetAddress > > * lh = ( const Hashtable < uint64_t , std : : vector < InetAddress > > * ) 0 ;
2016-11-22 18:54:58 +00:00
if ( family < 0 )
lh = ( _node - > prng ( ) & 1 ) ? & _v4Hints : & _v6Hints ;
else if ( family = = AF_INET )
lh = & _v4Hints ;
else if ( family = = AF_INET6 )
lh = & _v6Hints ;
else return 0 ;
2020-11-25 19:05:36 +00:00
const std : : vector < InetAddress > * l = lh - > get ( ztaddr ) ;
if ( ( l ) & & ( ! l - > empty ( ) ) ) {
memcpy ( result , & ( ( * l ) [ ( unsigned long ) _node - > prng ( ) % l - > size ( ) ] ) , sizeof ( struct sockaddr_storage ) ) ;
2016-11-22 18:54:58 +00:00
return 1 ;
2020-11-25 19:05:36 +00:00
}
else return 0 ;
2016-11-22 18:54:58 +00:00
}
2020-11-25 19:05:36 +00:00
inline void tapFrameHandler ( uint64_t nwid , const MAC & from , const MAC & to , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )
2015-04-15 00:57:51 +00:00
{
2020-11-25 19:05:36 +00:00
_node - > processVirtualNetworkFrame ( ( void * ) 0 , OSUtils : : now ( ) , nwid , from . toInt ( ) , to . toInt ( ) , etherType , vlanId , data , len , & _nextBackgroundTaskDeadline ) ;
2015-04-10 01:14:27 +00:00
}
2020-11-25 19:05:36 +00:00
inline void onHttpResponseFromClient ( TcpConnection * tc )
2015-04-11 02:08:49 +00:00
{
2017-06-05 19:15:28 +00:00
_phy . close ( tc - > sock ) ;
2015-04-11 02:08:49 +00:00
}
2020-11-25 19:05:36 +00:00
bool shouldBindInterface ( const char * ifname , const InetAddress & ifaddr )
2016-04-05 22:44:08 +00:00
{
2016-12-12 22:43:09 +00:00
# if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
2020-11-25 19:05:36 +00:00
if ( ( ifname [ 0 ] = = ' l ' ) & & ( ifname [ 1 ] = = ' o ' ) ) return false ; // loopback
if ( ( ifname [ 0 ] = = ' z ' ) & & ( ifname [ 1 ] = = ' t ' ) ) return false ; // sanity check: zt#
if ( ( ifname [ 0 ] = = ' t ' ) & & ( ifname [ 1 ] = = ' u ' ) & & ( ifname [ 2 ] = = ' n ' ) ) return false ; // tun# is probably an OpenVPN tunnel or similar
if ( ( ifname [ 0 ] = = ' t ' ) & & ( ifname [ 1 ] = = ' a ' ) & & ( ifname [ 2 ] = = ' p ' ) ) return false ; // tap# is probably an OpenVPN tunnel or similar
2016-12-12 22:43:09 +00:00
# endif
2016-04-05 22:44:08 +00:00
2016-12-12 22:43:09 +00:00
# ifdef __APPLE__
2020-11-25 19:05:36 +00:00
if ( ( ifname [ 0 ] = = ' f ' ) & & ( ifname [ 1 ] = = ' e ' ) & & ( ifname [ 2 ] = = ' t ' ) & & ( ifname [ 3 ] = = ' h ' ) ) return false ; // ... as is feth#
if ( ( ifname [ 0 ] = = ' l ' ) & & ( ifname [ 1 ] = = ' o ' ) ) return false ; // loopback
if ( ( ifname [ 0 ] = = ' z ' ) & & ( ifname [ 1 ] = = ' t ' ) ) return false ; // sanity check: zt#
if ( ( ifname [ 0 ] = = ' t ' ) & & ( ifname [ 1 ] = = ' u ' ) & & ( ifname [ 2 ] = = ' n ' ) ) return false ; // tun# is probably an OpenVPN tunnel or similar
if ( ( ifname [ 0 ] = = ' t ' ) & & ( ifname [ 1 ] = = ' a ' ) & & ( ifname [ 2 ] = = ' p ' ) ) return false ; // tap# is probably an OpenVPN tunnel or similar
if ( ( ifname [ 0 ] = = ' u ' ) & & ( ifname [ 1 ] = = ' t ' ) & & ( ifname [ 2 ] = = ' u ' ) & & ( ifname [ 3 ] = = ' n ' ) ) return false ; // ... as is utun#
# endif
2020-11-25 20:03:17 +00:00
# ifdef __FreeBSD__
if ( ( ifname [ 0 ] = = ' l ' ) & & ( ifname [ 1 ] = = ' o ' ) ) return false ; // loopback
if ( ( ifname [ 0 ] = = ' z ' ) & & ( ifname [ 1 ] = = ' t ' ) ) return false ; // sanity check: zt#
# endif
2016-12-12 22:43:09 +00:00
{
Mutex : : Lock _l ( _localConfig_m ) ;
for ( std : : vector < std : : string > : : const_iterator p ( _interfacePrefixBlacklist . begin ( ) ) ; p ! = _interfacePrefixBlacklist . end ( ) ; + + p ) {
2016-12-12 22:44:21 +00:00
if ( ! strncmp ( p - > c_str ( ) , ifname , p - > length ( ) ) )
2016-12-12 22:43:09 +00:00
return false ;
}
}
2018-02-03 19:53:46 +00:00
{
// Check global blacklists
const std : : vector < InetAddress > * gbl = ( const std : : vector < InetAddress > * ) 0 ;
if ( ifaddr . ss_family = = AF_INET ) {
gbl = & _globalV4Blacklist ;
} else if ( ifaddr . ss_family = = AF_INET6 ) {
gbl = & _globalV6Blacklist ;
}
if ( gbl ) {
Mutex : : Lock _l ( _localConfig_m ) ;
for ( std : : vector < InetAddress > : : const_iterator a ( gbl - > begin ( ) ) ; a ! = gbl - > end ( ) ; + + a ) {
if ( a - > containsAddress ( ifaddr ) )
2016-04-05 22:44:08 +00:00
return false ;
}
}
}
2016-12-12 22:43:09 +00:00
{
Mutex : : Lock _l ( _nets_m ) ;
for ( std : : map < uint64_t , NetworkState > : : const_iterator n ( _nets . begin ( ) ) ; n ! = _nets . end ( ) ; + + n ) {
2021-11-18 20:39:55 +00:00
if ( n - > second . tap ( ) ) {
std : : vector < InetAddress > ips ( n - > second . tap ( ) - > ips ( ) ) ;
2016-12-12 22:43:09 +00:00
for ( std : : vector < InetAddress > : : const_iterator i ( ips . begin ( ) ) ; i ! = ips . end ( ) ; + + i ) {
if ( i - > ipsEqual ( ifaddr ) )
return false ;
}
2021-03-16 14:12:55 +00:00
# ifdef _WIN32
2021-12-08 20:14:15 +00:00
if ( n - > second . tap ( ) - > friendlyName ( ) = = ifname )
2021-03-16 14:12:55 +00:00
return false ;
# endif
2016-04-05 22:44:08 +00:00
}
}
}
return true ;
}
2021-08-31 20:47:00 +00:00
unsigned int _getRandomPort ( )
{
unsigned int randp = 0 ;
Utils : : getSecureRandom ( & randp , sizeof ( randp ) ) ;
randp = 20000 + ( randp % 45500 ) ;
for ( int i = 0 ; ; + + i ) {
if ( i > 1000 ) {
return 0 ;
} else if ( + + randp > = 65536 ) {
randp = 20000 ;
}
if ( _trialBind ( randp ) )
break ;
}
2021-09-02 01:55:54 +00:00
return randp ;
2021-08-31 20:47:00 +00:00
}
2016-04-05 22:44:08 +00:00
bool _trialBind ( unsigned int port )
{
struct sockaddr_in in4 ;
struct sockaddr_in6 in6 ;
PhySocket * tb ;
memset ( & in4 , 0 , sizeof ( in4 ) ) ;
in4 . sin_family = AF_INET ;
in4 . sin_port = Utils : : hton ( ( uint16_t ) port ) ;
tb = _phy . udpBind ( reinterpret_cast < const struct sockaddr * > ( & in4 ) , ( void * ) 0 , 0 ) ;
if ( tb ) {
_phy . close ( tb , false ) ;
tb = _phy . tcpListen ( reinterpret_cast < const struct sockaddr * > ( & in4 ) , ( void * ) 0 ) ;
if ( tb ) {
_phy . close ( tb , false ) ;
return true ;
}
}
memset ( & in6 , 0 , sizeof ( in6 ) ) ;
in6 . sin6_family = AF_INET6 ;
in6 . sin6_port = Utils : : hton ( ( uint16_t ) port ) ;
tb = _phy . udpBind ( reinterpret_cast < const struct sockaddr * > ( & in6 ) , ( void * ) 0 , 0 ) ;
if ( tb ) {
_phy . close ( tb , false ) ;
tb = _phy . tcpListen ( reinterpret_cast < const struct sockaddr * > ( & in6 ) , ( void * ) 0 ) ;
if ( tb ) {
_phy . close ( tb , false ) ;
return true ;
}
}
return false ;
}
2015-04-10 01:14:27 +00:00
} ;
2017-03-28 00:03:17 +00:00
static int SnodeVirtualNetworkConfigFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t nwid , void * * nuptr , enum ZT_VirtualNetworkConfigOperation op , const ZT_VirtualNetworkConfig * nwconf )
2016-01-12 19:34:22 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeVirtualNetworkConfigFunction ( nwid , nuptr , op , nwconf ) ; }
2017-03-28 00:03:17 +00:00
static void SnodeEventCallback ( ZT_Node * node , void * uptr , void * tptr , enum ZT_Event event , const void * metaData )
2015-04-15 21:42:26 +00:00
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeEventCallback ( event , metaData ) ; }
2017-07-01 00:32:07 +00:00
static void SnodeStatePutFunction ( ZT_Node * node , void * uptr , void * tptr , enum ZT_StateObjectType type , const uint64_t id [ 2 ] , const void * data , int len )
2017-06-02 03:32:43 +00:00
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeStatePutFunction ( type , id , data , len ) ; }
2017-07-01 00:32:07 +00:00
static int SnodeStateGetFunction ( ZT_Node * node , void * uptr , void * tptr , enum ZT_StateObjectType type , const uint64_t id [ 2 ] , void * data , unsigned int maxlen )
2017-06-02 03:32:43 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeStateGetFunction ( type , id , data , maxlen ) ; }
2017-07-06 18:45:22 +00:00
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 ) ; }
2017-03-28 00:03:17 +00:00
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 )
2016-01-12 19:34:22 +00:00
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeVirtualNetworkFrameFunction ( nwid , nuptr , sourceMac , destMac , etherType , vlanId , data , len ) ; }
2017-07-06 18:45:22 +00:00
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 ) ; }
2017-03-28 00:03:17 +00:00
static int SnodePathLookupFunction ( ZT_Node * node , void * uptr , void * tptr , uint64_t ztaddr , int family , struct sockaddr_storage * result )
2016-11-22 18:54:58 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodePathLookupFunction ( ztaddr , family , result ) ; }
2017-03-28 00:03:17 +00:00
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 )
2015-04-15 21:42:26 +00:00
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > tapFrameHandler ( nwid , from , to , etherType , vlanId , data , len ) ; }
2015-04-15 00:57:51 +00:00
2015-04-11 02:08:49 +00:00
static int ShttpOnMessageBegin ( http_parser * parser )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
tc - > currentHeaderField = " " ;
tc - > currentHeaderValue = " " ;
tc - > messageSize = 0 ;
2017-06-05 19:15:28 +00:00
tc - > url . clear ( ) ;
tc - > status . clear ( ) ;
2015-04-28 19:43:10 +00:00
tc - > headers . clear ( ) ;
2017-06-05 19:15:28 +00:00
tc - > readq . clear ( ) ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
static int ShttpOnUrl ( http_parser * parser , const char * ptr , size_t length )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
tc - > messageSize + = ( unsigned long ) length ;
if ( tc - > messageSize > ZT_MAX_HTTP_MESSAGE_SIZE )
2015-04-11 02:08:49 +00:00
return - 1 ;
2015-04-28 19:43:10 +00:00
tc - > url . append ( ptr , length ) ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
2016-06-08 19:49:07 +00:00
# if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
2015-04-11 02:08:49 +00:00
static int ShttpOnStatus ( http_parser * parser , const char * ptr , size_t length )
2016-06-08 19:49:07 +00:00
# else
static int ShttpOnStatus ( http_parser * parser )
# endif
2017-06-05 19:15:28 +00:00
{ return 0 ; }
2015-04-11 02:08:49 +00:00
static int ShttpOnHeaderField ( http_parser * parser , const char * ptr , size_t length )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
tc - > messageSize + = ( unsigned long ) length ;
if ( tc - > messageSize > ZT_MAX_HTTP_MESSAGE_SIZE )
2015-04-11 02:08:49 +00:00
return - 1 ;
2015-04-28 19:43:10 +00:00
if ( ( tc - > currentHeaderField . length ( ) ) & & ( tc - > currentHeaderValue . length ( ) ) ) {
tc - > headers [ tc - > currentHeaderField ] = tc - > currentHeaderValue ;
tc - > currentHeaderField = " " ;
tc - > currentHeaderValue = " " ;
2015-04-11 02:08:49 +00:00
}
for ( size_t i = 0 ; i < length ; + + i )
2015-04-28 19:43:10 +00:00
tc - > currentHeaderField . push_back ( OSUtils : : toLower ( ptr [ i ] ) ) ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
static int ShttpOnValue ( http_parser * parser , const char * ptr , size_t length )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
tc - > messageSize + = ( unsigned long ) length ;
if ( tc - > messageSize > ZT_MAX_HTTP_MESSAGE_SIZE )
2015-04-11 02:08:49 +00:00
return - 1 ;
2015-04-28 19:43:10 +00:00
tc - > currentHeaderValue . append ( ptr , length ) ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
static int ShttpOnHeadersComplete ( http_parser * parser )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
if ( ( tc - > currentHeaderField . length ( ) ) & & ( tc - > currentHeaderValue . length ( ) ) )
tc - > headers [ tc - > currentHeaderField ] = tc - > currentHeaderValue ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
static int ShttpOnBody ( http_parser * parser , const char * ptr , size_t length )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
tc - > messageSize + = ( unsigned long ) length ;
if ( tc - > messageSize > ZT_MAX_HTTP_MESSAGE_SIZE )
2015-04-11 02:08:49 +00:00
return - 1 ;
2017-06-05 19:15:28 +00:00
tc - > readq . append ( ptr , length ) ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
static int ShttpOnMessageComplete ( http_parser * parser )
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( parser - > data ) ;
if ( tc - > type = = TcpConnection : : TCP_HTTP_INCOMING ) {
2015-04-11 02:08:49 +00:00
} else {
2015-04-28 19:43:10 +00:00
tc - > parent - > onHttpResponseFromClient ( tc ) ;
2015-04-11 02:08:49 +00:00
}
return 0 ;
}
2015-05-20 23:35:33 +00:00
} // anonymous namespace
2015-04-15 21:42:26 +00:00
std : : string OneService : : platformDefaultHomePath ( )
2015-04-10 02:58:04 +00:00
{
2016-06-23 19:37:15 +00:00
return OSUtils : : platformDefaultHomePath ( ) ;
2015-04-10 02:58:04 +00:00
}
2015-10-13 15:49:36 +00:00
OneService * OneService : : newInstance ( const char * hp , unsigned int port ) { return new OneServiceImpl ( hp , port ) ; }
2015-04-15 21:42:26 +00:00
OneService : : ~ OneService ( ) { }
2015-04-10 01:14:27 +00:00
} // namespace ZeroTier