2015-04-10 01:14:27 +00:00
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright ( C ) 2011 - 2015 ZeroTier , Inc .
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* - -
*
* ZeroTier may be used and distributed under the terms of the GPLv3 , which
* are available at : http : //www.gnu.org/licenses/gpl-3.0.html
*
* If you would like to embed ZeroTier into a commercial application or
* redistribute it in a modified binary form , please contact ZeroTier Networks
* LLC . Start here : http : //www.zerotier.com/
*/
# 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>
2015-04-14 01:43:33 +00:00
# include <set>
2015-04-11 00:07:06 +00:00
# include <vector>
# include <algorithm>
2015-04-10 01:14:27 +00:00
# include "../version.h"
# include "../include/ZeroTierOne.h"
2015-04-11 00:07:06 +00:00
# include "../ext/http-parser/http_parser.h"
2015-04-10 01:14:27 +00:00
# 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"
2015-04-10 01:14:27 +00:00
# include "../osdep/Phy.hpp"
2015-05-21 02:38:49 +00:00
# include "../osdep/Thread.hpp"
2015-04-10 01:14:27 +00:00
# include "../osdep/OSUtils.hpp"
2015-05-21 02:38:49 +00:00
# include "../osdep/Http.hpp"
2015-05-21 22:22:41 +00:00
# include "../osdep/BackgroundResolver.hpp"
2015-07-28 21:32:02 +00:00
# include "../osdep/UPNPClient.hpp"
2015-04-10 01:14:27 +00:00
2015-04-15 21:42:26 +00:00
# include "OneService.hpp"
2015-04-14 01:12:45 +00:00
# include "ControlPlane.hpp"
2015-04-10 01:14:27 +00:00
2015-05-22 21:52:23 +00:00
/**
* Uncomment to enable UDP breakage switch
*
* If this is defined , the presence of a file called / tmp / ZT_BREAK_UDP
* will cause direct UDP TX / RX to stop working . This can be used to
* test TCP tunneling fallback and other robustness features . Deleting
* this file will cause it to start working again .
*/
//#define ZT_BREAK_UDP
2015-05-17 22:51:07 +00:00
# ifdef ZT_ENABLE_NETWORK_CONTROLLER
# include "../controller/SqliteNetworkController.hpp"
# else
class SqliteNetworkController ;
2015-05-21 02:38:49 +00:00
# endif // ZT_ENABLE_NETWORK_CONTROLLER
2015-05-17 22:51:07 +00:00
2015-04-24 22:05:28 +00:00
# ifdef __WINDOWS__
2015-07-07 00:22:37 +00:00
# include <WinSock2.h>
# include <Windows.h>
2015-04-24 22:05:28 +00:00
# include <ShlObj.h>
2015-07-07 00:22:37 +00:00
# include <netioapi.h>
# include <iphlpapi.h>
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>
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
2015-04-20 22:12:31 +00:00
// Include the right tap device driver for this platform -- add new platforms here
2015-04-14 22:55:03 +00:00
# ifdef __APPLE__
# include "../osdep/OSXEthernetTap.hpp"
namespace ZeroTier { typedef OSXEthernetTap EthernetTap ; }
2015-04-20 22:12:31 +00:00
# endif
# ifdef __LINUX__
# include "../osdep/LinuxEthernetTap.hpp"
namespace ZeroTier { typedef LinuxEthernetTap EthernetTap ; }
2015-04-14 22:55:03 +00:00
# endif
2015-04-24 22:05:28 +00:00
# ifdef __WINDOWS__
# include "../osdep/WindowsEthernetTap.hpp"
namespace ZeroTier { typedef WindowsEthernetTap EthernetTap ; }
# endif
2015-05-25 18:11:37 +00:00
# ifdef __FreeBSD__
2015-05-15 15:48:53 +00:00
# include "../osdep/BSDEthernetTap.hpp"
namespace ZeroTier { typedef BSDEthernetTap EthernetTap ; }
# endif
2015-04-14 22:55:03 +00:00
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)
2015-04-11 02:08:49 +00:00
# define ZT_MAX_HTTP_CONNECTIONS 64
2015-04-15 00:57:51 +00:00
// Interface metric for ZeroTier taps
# define ZT_IF_METRIC 32768
// How often to check for new multicast subscriptions on a tap device
# define ZT_TAP_CHECK_MULTICAST_INTERVAL 30000
2015-05-17 22:51:07 +00:00
// Path under ZT1 home for controller database if controller is enabled
# define ZT1_CONTROLLER_DB_PATH "controller.db"
2015-05-22 01:33:52 +00:00
// TCP fallback relay host -- geo-distributed using Amazon Route53 geo-aware DNS
2015-05-21 22:22:41 +00:00
# define ZT1_TCP_FALLBACK_RELAY "tcp-fallback.zerotier.com"
2015-05-22 01:33:52 +00:00
# define ZT1_TCP_FALLBACK_RELAY_PORT 443
2015-05-21 22:22:41 +00:00
// Frequency at which we re-resolve the TCP fallback relay
# define ZT1_TCP_FALLBACK_RERESOLVE_DELAY 86400000
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
# define ZT1_TCP_FALLBACK_AFTER 60000
2015-07-06 23:32:34 +00:00
// How often to check for local interface addresses
# define ZT1_LOCAL_INTERFACE_CHECK_INTERVAL 300000
2015-04-10 01:14:27 +00:00
namespace ZeroTier {
2015-05-20 23:35:33 +00:00
namespace {
2015-05-21 02:38:49 +00:00
# ifdef ZT_AUTO_UPDATE
# define ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE (1024 * 1024 * 64)
2015-05-21 03:17:56 +00:00
# define ZT_AUTO_UPDATE_CHECK_PERIOD 21600000
2015-05-21 02:38:49 +00:00
class BackgroundSoftwareUpdateChecker
{
public :
bool isValidSigningIdentity ( const Identity & id )
{
return (
/* 0005 */ ( id = = Identity ( " ba57ea350e:0:9d4be6d7f86c5660d5ee1951a3d759aa6e12a84fc0c0b74639500f1dbc1a8c566622e7d1c531967ebceb1e9d1761342f88324a8ba520c93c35f92f35080fa23f " ) )
/* 0006 */ | | ( id = = Identity ( " 5067b21b83:0:8af477730f5055c48135b84bed6720a35bca4c0e34be4060a4c636288b1ec22217eb22709d610c66ed464c643130c51411bbb0294eef12fbe8ecc1a1e2c63a7a " ) )
/* 0007 */ | | ( id = = Identity ( " 4f5e97a8f1:0:57880d056d7baeb04bbc057d6f16e6cb41388570e87f01492fce882485f65a798648595610a3ad49885604e7fb1db2dd3c2c534b75e42c3c0b110ad07b4bb138 " ) )
/* 0008 */ | | ( id = = Identity ( " 580bbb8e15:0:ad5ef31155bebc6bc413991992387e083fed26d699997ef76e7c947781edd47d1997161fa56ba337b1a2b44b129fd7c7197ce5185382f06011bc88d1363b4ddd " ) )
) ;
}
void doUpdateCheck ( )
{
std : : string url ( OneService : : autoUpdateUrl ( ) ) ;
if ( ( url . length ( ) < = 7 ) | | ( url . substr ( 0 , 7 ) ! = " http:// " ) )
return ;
std : : string httpHost ;
std : : string httpPath ;
{
std : : size_t slashIdx = url . substr ( 7 ) . find_first_of ( ' / ' ) ;
if ( slashIdx = = std : : string : : npos ) {
httpHost = url . substr ( 7 ) ;
httpPath = " / " ;
} else {
httpHost = url . substr ( 7 , slashIdx ) ;
httpPath = url . substr ( slashIdx + 7 ) ;
}
}
if ( httpHost . length ( ) = = 0 )
return ;
std : : vector < InetAddress > ips ( OSUtils : : resolve ( httpHost . c_str ( ) ) ) ;
for ( std : : vector < InetAddress > : : iterator ip ( ips . begin ( ) ) ; ip ! = ips . end ( ) ; + + ip ) {
if ( ! ip - > port ( ) )
ip - > setPort ( 80 ) ;
std : : string nfoPath = httpPath + " LATEST.nfo " ;
std : : map < std : : string , std : : string > requestHeaders , responseHeaders ;
std : : string body ;
requestHeaders [ " Host " ] = httpHost ;
unsigned int scode = Http : : GET ( ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE , 60000 , reinterpret_cast < const struct sockaddr * > ( & ( * ip ) ) , nfoPath . c_str ( ) , requestHeaders , responseHeaders , body ) ;
//fprintf(stderr,"UPDATE %s %s %u %lu\n",ip->toString().c_str(),nfoPath.c_str(),scode,body.length());
if ( ( scode = = 200 ) & & ( body . length ( ) > 0 ) ) {
/* NFO fields:
*
* file = < filename >
* signedBy = < signing identity >
* ed25519 = < ed25519 ECC signature of archive >
* vMajor = < major version >
* vMinor = < minor version >
* vRevision = < revision > */
Dictionary nfo ( body ) ;
unsigned int vMajor = Utils : : strToUInt ( nfo . get ( " vMajor " , " 0 " ) . c_str ( ) ) ;
unsigned int vMinor = Utils : : strToUInt ( nfo . get ( " vMinor " , " 0 " ) . c_str ( ) ) ;
unsigned int vRevision = Utils : : strToUInt ( nfo . get ( " vRevision " , " 0 " ) . c_str ( ) ) ;
if ( Utils : : compareVersion ( vMajor , vMinor , vRevision , ZEROTIER_ONE_VERSION_MAJOR , ZEROTIER_ONE_VERSION_MINOR , ZEROTIER_ONE_VERSION_REVISION ) < = 0 ) {
//fprintf(stderr,"UPDATE %u.%u.%u is not newer than our version\n",vMajor,vMinor,vRevision);
return ;
}
Identity signedBy ;
if ( ( ! signedBy . fromString ( nfo . get ( " signedBy " , " " ) ) ) | | ( ! isValidSigningIdentity ( signedBy ) ) ) {
//fprintf(stderr,"UPDATE invalid signedBy or not authorized signing identity.\n");
return ;
}
std : : string filePath ( nfo . get ( " file " , " " ) ) ;
if ( ( ! filePath . length ( ) ) | | ( filePath . find ( " .. " ) ! = std : : string : : npos ) )
return ;
filePath = httpPath + filePath ;
std : : string fileData ;
if ( Http : : GET ( ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE , 60000 , reinterpret_cast < const struct sockaddr * > ( & ( * ip ) ) , filePath . c_str ( ) , requestHeaders , responseHeaders , fileData ) ! = 200 ) {
//fprintf(stderr,"UPDATE GET %s failed\n",filePath.c_str());
return ;
}
2015-06-03 23:25:16 +00:00
std : : string ed25519 ( Utils : : unhex ( nfo . get ( " ed25519 " , " " ) ) ) ;
2015-05-21 02:38:49 +00:00
if ( ( ed25519 . length ( ) = = 0 ) | | ( ! signedBy . verify ( fileData . data ( ) , ( unsigned int ) fileData . length ( ) , ed25519 . data ( ) , ( unsigned int ) ed25519 . length ( ) ) ) ) {
//fprintf(stderr,"UPDATE %s failed signature check!\n",filePath.c_str());
return ;
}
/* --------------------------------------------------------------- */
/* We made it! Begin OS-specific installation code. */
# ifdef __APPLE__
/* OSX version is in the form of a MacOSX .pkg file, so we will
* launch installer ( normally in / usr / sbin ) to install it . It will
* then turn around and shut down the service , update files , and
* relaunch . */
{
char bashp [ 128 ] , pkgp [ 128 ] ;
Utils : : snprintf ( bashp , sizeof ( bashp ) , " /tmp/ZeroTierOne-update-%u.%u.%u.sh " , vMajor , vMinor , vRevision ) ;
Utils : : snprintf ( pkgp , sizeof ( pkgp ) , " /tmp/ZeroTierOne-update-%u.%u.%u.pkg " , vMajor , vMinor , vRevision ) ;
FILE * pkg = fopen ( pkgp , " w " ) ;
if ( ( ! pkg ) | | ( fwrite ( fileData . data ( ) , fileData . length ( ) , 1 , pkg ) ! = 1 ) ) {
fclose ( pkg ) ;
unlink ( bashp ) ;
unlink ( pkgp ) ;
fprintf ( stderr , " UPDATE error writing %s \n " , pkgp ) ;
return ;
}
fclose ( pkg ) ;
FILE * bash = fopen ( bashp , " w " ) ;
if ( ! bash ) {
fclose ( pkg ) ;
unlink ( bashp ) ;
unlink ( pkgp ) ;
fprintf ( stderr , " UPDATE error writing %s \n " , bashp ) ;
return ;
}
fprintf ( bash ,
" #!/bin/bash \n "
" export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin \n "
2015-06-02 23:54:27 +00:00
" sleep 1 \n "
2015-05-21 02:38:49 +00:00
" installer -pkg \" %s \" -target / \n "
" sleep 1 \n "
" rm -f \" %s \" \" %s \" \n "
" exit 0 \n " ,
pkgp ,
pkgp ,
bashp ) ;
fclose ( bash ) ;
long pid = ( long ) vfork ( ) ;
if ( pid = = 0 ) {
2015-06-03 23:37:24 +00:00
setsid ( ) ; // detach from parent so that shell isn't killed when parent is killed
signal ( SIGHUP , SIG_IGN ) ;
signal ( SIGTERM , SIG_IGN ) ;
signal ( SIGQUIT , SIG_IGN ) ;
2015-05-21 02:38:49 +00:00
execl ( " /bin/bash " , " /bin/bash " , bashp , ( char * ) 0 ) ;
exit ( 0 ) ;
}
}
# endif // __APPLE__
# ifdef __WINDOWS__
/* Windows version comes in the form of .MSI package that
* takes care of everything . */
{
2015-05-21 03:17:56 +00:00
char tempp [ 512 ] , batp [ 512 ] , msip [ 512 ] , cmdline [ 512 ] ;
if ( GetTempPathA ( sizeof ( tempp ) , tempp ) < = 0 )
return ;
CreateDirectoryA ( tempp , ( LPSECURITY_ATTRIBUTES ) 0 ) ;
Utils : : snprintf ( batp , sizeof ( batp ) , " %s \\ ZeroTierOne-update-%u.%u.%u.bat " , tempp , vMajor , vMinor , vRevision ) ;
Utils : : snprintf ( msip , sizeof ( msip ) , " %s \\ ZeroTierOne-update-%u.%u.%u.msi " , tempp , vMajor , vMinor , vRevision ) ;
FILE * msi = fopen ( msip , " wb " ) ;
if ( ( ! msi ) | | ( fwrite ( fileData . data ( ) , ( size_t ) fileData . length ( ) , 1 , msi ) ! = 1 ) ) {
fclose ( msi ) ;
return ;
}
fclose ( msi ) ;
FILE * bat = fopen ( batp , " wb " ) ;
if ( ! bat )
return ;
fprintf ( bat ,
" TIMEOUT.EXE /T 1 /NOBREAK \r \n "
" NET.EXE STOP \" ZeroTierOneService \" \r \n "
" TIMEOUT.EXE /T 1 /NOBREAK \r \n "
" MSIEXEC.EXE /i \" %s \" /qn \r \n "
" TIMEOUT.EXE /T 1 /NOBREAK \r \n "
" NET.EXE START \" ZeroTierOneService \" \r \n "
" DEL \" %s \" \r \n "
" DEL \" %s \" \r \n " ,
msip ,
msip ,
batp ) ;
fclose ( bat ) ;
STARTUPINFOA si ;
PROCESS_INFORMATION pi ;
memset ( & si , 0 , sizeof ( si ) ) ;
memset ( & pi , 0 , sizeof ( pi ) ) ;
Utils : : snprintf ( cmdline , sizeof ( cmdline ) , " CMD.EXE /c \" %s \" " , batp ) ;
CreateProcessA ( NULL , cmdline , NULL , NULL , FALSE , CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP , NULL , NULL , & si , & pi ) ;
2015-05-21 02:38:49 +00:00
}
# endif // __WINDOWS__
/* --------------------------------------------------------------- */
return ;
} // else try to fetch from next IP address
}
}
void threadMain ( )
throw ( )
{
try {
this - > doUpdateCheck ( ) ;
} catch ( . . . ) { }
}
} ;
static BackgroundSoftwareUpdateChecker backgroundSoftwareUpdateChecker ;
# endif // ZT_AUTO_UPDATE
2015-04-15 21:42:26 +00:00
class OneServiceImpl ;
2015-04-11 02:08:49 +00:00
2015-04-10 01:14:27 +00:00
static int SnodeVirtualNetworkConfigFunction ( ZT1_Node * node , void * uptr , uint64_t nwid , enum ZT1_VirtualNetworkConfigOperation op , const ZT1_VirtualNetworkConfig * nwconf ) ;
static void SnodeEventCallback ( ZT1_Node * node , void * uptr , enum ZT1_Event event , const void * metaData ) ;
static long SnodeDataStoreGetFunction ( ZT1_Node * node , void * uptr , const char * name , void * buf , unsigned long bufSize , unsigned long readIndex , unsigned long * totalSize ) ;
static int SnodeDataStorePutFunction ( ZT1_Node * node , void * uptr , const char * name , const void * data , unsigned long len , int secure ) ;
2015-09-23 20:49:56 +00:00
static int SnodeWirePacketSendFunction ( ZT1_Node * node , void * uptr , int localInterfaceId , const struct sockaddr_storage * addr , const void * data , unsigned int len ) ;
2015-04-10 01:14:27 +00:00
static void SnodeVirtualNetworkFrameFunction ( ZT1_Node * node , void * uptr , uint64_t nwid , uint64_t sourceMac , uint64_t destMac , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len ) ;
2015-04-15 00:57:51 +00:00
static void StapFrameHandler ( void * uptr , uint64_t nwid , const MAC & from , const MAC & to , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len ) ;
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 ) ;
static int ShttpOnStatus ( http_parser * parser , const char * ptr , size_t length ) ;
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 ) ;
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
} ;
2015-04-11 00:07:06 +00:00
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 {
TCP_HTTP_INCOMING ,
TCP_HTTP_OUTGOING , // not currently used
TCP_TUNNEL_OUTGOING // fale-SSL outgoing tunnel -- HTTP-related fields are not used
} type ;
2015-04-11 02:08:49 +00:00
bool shouldKeepAlive ;
2015-04-15 21:42:26 +00:00
OneServiceImpl * parent ;
2015-04-11 02:08:49 +00:00
PhySocket * sock ;
2015-04-11 02:36:29 +00:00
InetAddress from ;
2015-04-11 02:08:49 +00:00
http_parser parser ;
unsigned long messageSize ;
uint64_t lastActivity ;
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
std : : string body ;
std : : string writeBuf ;
2015-05-22 21:52:23 +00:00
Mutex writeBuf_m ;
2015-04-11 02:08:49 +00:00
} ;
2015-04-11 00:07:06 +00:00
2015-04-15 21:42:26 +00:00
class OneServiceImpl : public OneService
2015-04-10 01:14:27 +00:00
{
public :
2015-05-17 22:51:07 +00:00
OneServiceImpl ( const char * hp , unsigned int port , const char * overrideRootTopology ) :
2015-04-10 02:58:04 +00:00
_homePath ( ( hp ) ? hp : " . " ) ,
2015-05-21 22:22:41 +00:00
_tcpFallbackResolver ( ZT1_TCP_FALLBACK_RELAY ) ,
2015-05-17 22:51:07 +00:00
# ifdef ZT_ENABLE_NETWORK_CONTROLLER
_controller ( ( _homePath + ZT_PATH_SEPARATOR_S + ZT1_CONTROLLER_DB_PATH ) . c_str ( ) ) ,
# endif
2015-07-28 17:29:25 +00:00
_phy ( this , false , true ) ,
2015-04-10 01:14:27 +00:00
_overrideRootTopology ( ( overrideRootTopology ) ? overrideRootTopology : " " ) ,
_node ( ( Node * ) 0 ) ,
2015-04-14 01:12:45 +00:00
_controlPlane ( ( ControlPlane * ) 0 ) ,
2015-05-22 01:33:52 +00:00
_lastDirectReceiveFromGlobal ( 0 ) ,
_lastSendToGlobal ( 0 ) ,
2015-05-22 21:52:23 +00:00
_lastRestart ( 0 ) ,
2015-04-10 01:14:27 +00:00
_nextBackgroundTaskDeadline ( 0 ) ,
2015-05-22 01:33:52 +00:00
_tcpFallbackTunnel ( ( TcpConnection * ) 0 ) ,
2015-04-10 01:14:27 +00:00
_termReason ( ONE_STILL_RUNNING ) ,
2015-07-06 23:32:34 +00:00
_port ( port ) ,
2015-07-28 21:32:02 +00:00
# ifdef ZT_USE_MINIUPNPC
_upnpClient ( ( int ) port ) ,
# endif
2015-04-10 01:14:27 +00:00
_run ( true )
{
struct sockaddr_in in4 ;
struct sockaddr_in6 in6 ;
2015-04-10 01:22:04 +00:00
: : memset ( ( void * ) & in4 , 0 , sizeof ( in4 ) ) ;
2015-04-10 01:14:27 +00:00
in4 . sin_family = AF_INET ;
2015-04-11 02:08:49 +00:00
in4 . sin_port = Utils : : hton ( ( uint16_t ) port ) ;
2015-04-10 01:14:27 +00:00
_v4UdpSocket = _phy . udpBind ( ( const struct sockaddr * ) & in4 , this , 131072 ) ;
if ( ! _v4UdpSocket )
throw std : : runtime_error ( " cannot bind to port (UDP/IPv4) " ) ;
2015-04-27 01:15:40 +00:00
in4 . sin_addr . s_addr = Utils : : hton ( ( uint32_t ) 0x7f000001 ) ; // right now we just listen for TCP @localhost
2015-04-10 01:14:27 +00:00
_v4TcpListenSocket = _phy . tcpListen ( ( const struct sockaddr * ) & in4 , this ) ;
if ( ! _v4TcpListenSocket ) {
_phy . close ( _v4UdpSocket ) ;
throw std : : runtime_error ( " cannot bind to port (TCP/IPv4) " ) ;
}
2015-04-10 01:22:04 +00:00
: : memset ( ( void * ) & in6 , 0 , sizeof ( in6 ) ) ;
in6 . sin6_family = AF_INET6 ;
in6 . sin6_port = in4 . sin_port ;
2015-04-10 01:14:27 +00:00
_v6UdpSocket = _phy . udpBind ( ( const struct sockaddr * ) & in6 , this , 131072 ) ;
2015-04-27 01:15:40 +00:00
in6 . sin6_addr . s6_addr [ 15 ] = 1 ; // listen for TCP only at localhost
2015-04-10 01:14:27 +00:00
_v6TcpListenSocket = _phy . tcpListen ( ( const struct sockaddr * ) & in6 , this ) ;
2015-04-16 02:38:01 +00:00
char portstr [ 64 ] ;
Utils : : snprintf ( portstr , sizeof ( portstr ) , " %u " , port ) ;
OSUtils : : writeFile ( ( _homePath + ZT_PATH_SEPARATOR_S + " zerotier-one.port " ) . c_str ( ) , std : : string ( portstr ) ) ;
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
{
_phy . close ( _v4UdpSocket ) ;
_phy . close ( _v6UdpSocket ) ;
_phy . close ( _v4TcpListenSocket ) ;
_phy . close ( _v6TcpListenSocket ) ;
}
2015-04-10 18:40:45 +00:00
virtual ReasonForTermination run ( )
{
try {
2015-04-16 02:14:12 +00:00
std : : string authToken ;
{
std : : string authTokenPath ( _homePath + ZT_PATH_SEPARATOR_S + " authtoken.secret " ) ;
if ( ! OSUtils : : readFile ( authTokenPath . c_str ( ) , authToken ) ) {
unsigned char foo [ 24 ] ;
Utils : : getSecureRandom ( foo , sizeof ( foo ) ) ;
authToken = " " ;
for ( unsigned int i = 0 ; i < sizeof ( foo ) ; + + i )
authToken . push_back ( " abcdefghijklmnopqrstuvwxyz0123456789 " [ ( unsigned long ) foo [ i ] % 36 ] ) ;
if ( ! OSUtils : : writeFile ( authTokenPath . c_str ( ) , authToken ) ) {
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = " authtoken.secret could not be written " ;
return _termReason ;
} else OSUtils : : lockDownFile ( authTokenPath . c_str ( ) , false ) ;
}
}
authToken = Utils : : trim ( authToken ) ;
2015-04-10 18:40:45 +00:00
_node = new Node (
OSUtils : : now ( ) ,
this ,
SnodeDataStoreGetFunction ,
SnodeDataStorePutFunction ,
SnodeWirePacketSendFunction ,
SnodeVirtualNetworkFrameFunction ,
SnodeVirtualNetworkConfigFunction ,
SnodeEventCallback ,
( ( _overrideRootTopology . length ( ) > 0 ) ? _overrideRootTopology . c_str ( ) : ( const char * ) 0 ) ) ;
2015-05-17 22:51:07 +00:00
# ifdef ZT_ENABLE_NETWORK_CONTROLLER
_node - > setNetconfMaster ( ( void * ) & _controller ) ;
# endif
2015-04-10 18:40:45 +00:00
2015-05-06 03:53:30 +00:00
_controlPlane = new ControlPlane ( this , _node , ( _homePath + ZT_PATH_SEPARATOR_S + " ui " ) . c_str ( ) ) ;
2015-04-16 02:14:12 +00:00
_controlPlane - > addAuthToken ( authToken . c_str ( ) ) ;
2015-05-17 22:51:07 +00:00
# ifdef ZT_ENABLE_NETWORK_CONTROLLER
_controlPlane - > setController ( & _controller ) ;
# endif
2015-04-14 01:12:45 +00:00
2015-04-14 22:55:03 +00:00
{ // Remember networks from previous session
2015-04-14 22:32:05 +00:00
std : : vector < std : : string > networksDotD ( OSUtils : : listDirectory ( ( _homePath + ZT_PATH_SEPARATOR_S + " networks.d " ) . c_str ( ) ) ) ;
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 " ) )
_node - > join ( Utils : : hexStrToU64 ( f - > substr ( 0 , dot ) . c_str ( ) ) ) ;
}
}
2015-04-10 18:40:45 +00:00
_nextBackgroundTaskDeadline = 0 ;
2015-05-22 21:52:23 +00:00
uint64_t clockShouldBe = OSUtils : : now ( ) ;
_lastRestart = clockShouldBe ;
2015-04-15 00:57:51 +00:00
uint64_t lastTapMulticastGroupCheck = 0 ;
2015-05-21 22:22:41 +00:00
uint64_t lastTcpFallbackResolve = 0 ;
2015-07-28 21:32:02 +00:00
uint64_t lastLocalInterfaceAddressCheck = ( OSUtils : : now ( ) - ZT1_LOCAL_INTERFACE_CHECK_INTERVAL ) + 15000 ; // do this in 15s to give UPnP time to configure and other things time to settle
2015-05-21 03:17:56 +00:00
# ifdef ZT_AUTO_UPDATE
uint64_t lastSoftwareUpdateCheck = 0 ;
# endif // ZT_AUTO_UPDATE
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 ;
} else _run_m . unlock ( ) ;
uint64_t now = OSUtils : : now ( ) ;
2015-05-22 21:52:23 +00:00
uint64_t dl = _nextBackgroundTaskDeadline ;
2015-04-10 18:40:45 +00:00
if ( dl < = now ) {
2015-04-11 02:08:49 +00:00
_node - > processBackgroundTasks ( now , & _nextBackgroundTaskDeadline ) ;
2015-04-10 18:40:45 +00:00
dl = _nextBackgroundTaskDeadline ;
2015-04-15 20:09:20 +00:00
}
2015-05-22 21:52:23 +00:00
// Attempt to detect sleep/wake events by detecting delay overruns
if ( ( now > clockShouldBe ) & & ( ( now - clockShouldBe ) > 2000 ) )
_lastRestart = now ;
2015-05-21 03:17:56 +00:00
# ifdef ZT_AUTO_UPDATE
if ( ( now - lastSoftwareUpdateCheck ) > = ZT_AUTO_UPDATE_CHECK_PERIOD ) {
lastSoftwareUpdateCheck = OSUtils : : now ( ) ;
Thread : : start ( & backgroundSoftwareUpdateChecker ) ;
}
# endif // ZT_AUTO_UPDATE
2015-05-21 22:22:41 +00:00
if ( ( now - lastTcpFallbackResolve ) > = ZT1_TCP_FALLBACK_RERESOLVE_DELAY ) {
lastTcpFallbackResolve = now ;
_tcpFallbackResolver . resolveNow ( ) ;
}
2015-05-22 01:33:52 +00:00
if ( ( _tcpFallbackTunnel ) & & ( ( now - _lastDirectReceiveFromGlobal ) < ( ZT1_TCP_FALLBACK_AFTER / 2 ) ) )
_phy . close ( _tcpFallbackTunnel - > sock ) ;
2015-04-15 20:09:20 +00:00
if ( ( now - lastTapMulticastGroupCheck ) > = ZT_TAP_CHECK_MULTICAST_INTERVAL ) {
lastTapMulticastGroupCheck = now ;
Mutex : : Lock _l ( _taps_m ) ;
for ( std : : map < uint64_t , EthernetTap * > : : const_iterator t ( _taps . begin ( ) ) ; t ! = _taps . end ( ) ; + + t ) {
std : : vector < MulticastGroup > added , removed ;
t - > second - > scanMulticastGroups ( added , removed ) ;
for ( std : : vector < MulticastGroup > : : iterator m ( added . begin ( ) ) ; m ! = added . end ( ) ; + + m )
_node - > multicastSubscribe ( t - > first , m - > mac ( ) . toInt ( ) , m - > adi ( ) ) ;
for ( std : : vector < MulticastGroup > : : iterator m ( removed . begin ( ) ) ; m ! = removed . end ( ) ; + + m )
_node - > multicastUnsubscribe ( t - > first , m - > mac ( ) . toInt ( ) , m - > adi ( ) ) ;
}
2015-04-10 18:40:45 +00:00
}
2015-07-06 23:32:34 +00:00
if ( ( now - lastLocalInterfaceAddressCheck ) > = ZT1_LOCAL_INTERFACE_CHECK_INTERVAL ) {
lastLocalInterfaceAddressCheck = now ;
# ifdef __UNIX_LIKE__
std : : vector < std : : string > ztDevices ;
{
Mutex : : Lock _l ( _taps_m ) ;
for ( std : : map < uint64_t , EthernetTap * > : : const_iterator t ( _taps . begin ( ) ) ; t ! = _taps . end ( ) ; + + t )
ztDevices . push_back ( t - > second - > deviceName ( ) ) ;
}
2015-07-28 21:32:02 +00:00
_node - > clearLocalInterfaceAddresses ( ) ;
# ifdef ZT_USE_MINIUPNPC
std : : vector < InetAddress > upnpAddresses ( _upnpClient . get ( ) ) ;
2015-07-28 21:48:26 +00:00
for ( std : : vector < InetAddress > : : const_iterator ext ( upnpAddresses . begin ( ) ) ; ext ! = upnpAddresses . end ( ) ; + + ext )
2015-07-28 21:32:02 +00:00
_node - > addLocalInterfaceAddress ( reinterpret_cast < const struct sockaddr_storage * > ( & ( * ext ) ) , 0 , ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL ) ;
# endif
2015-07-06 23:32:34 +00:00
struct ifaddrs * ifatbl = ( struct ifaddrs * ) 0 ;
if ( ( getifaddrs ( & ifatbl ) = = 0 ) & & ( ifatbl ) ) {
struct ifaddrs * ifa = ifatbl ;
while ( ifa ) {
if ( ( ifa - > ifa_name ) & & ( ifa - > ifa_addr ) ) {
bool isZT = false ;
for ( std : : vector < std : : string > : : const_iterator d ( ztDevices . begin ( ) ) ; d ! = ztDevices . end ( ) ; + + d ) {
if ( * d = = ifa - > ifa_name ) {
isZT = true ;
break ;
}
}
if ( ! isZT ) {
InetAddress ip ( ifa - > ifa_addr ) ;
2015-07-07 15:54:48 +00:00
ip . setPort ( _port ) ;
2015-07-13 17:03:04 +00:00
_node - > addLocalInterfaceAddress ( reinterpret_cast < const struct sockaddr_storage * > ( & ip ) , 0 , ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL ) ;
2015-07-06 23:32:34 +00:00
}
}
ifa = ifa - > ifa_next ;
}
freeifaddrs ( ifatbl ) ;
}
# endif // __UNIX_LIKE__
# ifdef __WINDOWS__
std : : vector < NET_LUID > ztDevices ;
{
Mutex : : Lock _l ( _taps_m ) ;
for ( std : : map < uint64_t , EthernetTap * > : : const_iterator t ( _taps . begin ( ) ) ; t ! = _taps . end ( ) ; + + t )
2015-07-07 00:22:37 +00:00
ztDevices . push_back ( t - > second - > luid ( ) ) ;
2015-07-06 23:32:34 +00:00
}
2015-07-07 00:22:37 +00:00
char aabuf [ 16384 ] ;
ULONG aalen = sizeof ( aabuf ) ;
if ( GetAdaptersAddresses ( AF_UNSPEC , GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER , ( void * ) 0 , reinterpret_cast < PIP_ADAPTER_ADDRESSES > ( aabuf ) , & aalen ) = = NO_ERROR ) {
PIP_ADAPTER_ADDRESSES a = reinterpret_cast < PIP_ADAPTER_ADDRESSES > ( aabuf ) ;
while ( a ) {
bool isZT = false ;
for ( std : : vector < NET_LUID > : : const_iterator d ( ztDevices . begin ( ) ) ; d ! = ztDevices . end ( ) ; + + d ) {
if ( a - > Luid . Value = = d - > Value ) {
isZT = true ;
break ;
}
}
if ( ! isZT ) {
PIP_ADAPTER_UNICAST_ADDRESS ua = a - > FirstUnicastAddress ;
while ( ua ) {
InetAddress ip ( ua - > Address . lpSockaddr ) ;
2015-07-07 15:54:48 +00:00
ip . setPort ( _port ) ;
2015-07-17 02:20:43 +00:00
_node - > addLocalInterfaceAddress ( reinterpret_cast < const struct sockaddr_storage * > ( & ip ) , 0 , ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL ) ;
2015-07-07 00:22:37 +00:00
ua = ua - > Next ;
}
}
a = a - > Next ;
}
}
2015-07-06 23:32:34 +00:00
# endif // __WINDOWS__
}
2015-04-10 18:40:45 +00:00
const unsigned long delay = ( dl > now ) ? ( unsigned long ) ( dl - now ) : 100 ;
2015-05-22 21:52:23 +00:00
clockShouldBe = now + ( uint64_t ) delay ;
2015-04-10 18:40:45 +00:00
_phy . poll ( delay ) ;
}
} catch ( std : : exception & exc ) {
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = exc . what ( ) ;
} catch ( . . . ) {
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = " unexpected exception in main thread " ;
}
2015-04-11 02:36:29 +00:00
try {
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
{
Mutex : : Lock _l ( _taps_m ) ;
for ( std : : map < uint64_t , EthernetTap * > : : iterator t ( _taps . begin ( ) ) ; t ! = _taps . end ( ) ; + + t )
delete t - > second ;
_taps . clear ( ) ;
}
2015-04-14 01:12:45 +00:00
delete _controlPlane ;
_controlPlane = ( ControlPlane * ) 0 ;
2015-04-10 18:40:45 +00:00
delete _node ;
_node = ( Node * ) 0 ;
return _termReason ;
}
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
{
Mutex : : Lock _l ( _taps_m ) ;
std : : map < uint64_t , EthernetTap * > : : const_iterator t ( _taps . find ( nwid ) ) ;
if ( t ! = _taps . end ( ) )
return t - > second - > deviceName ( ) ;
return std : : string ( ) ;
}
2015-05-22 21:52:23 +00:00
virtual bool tcpFallbackActive ( ) const
{
return ( _tcpFallbackTunnel ! = ( TcpConnection * ) 0 ) ;
}
2015-04-10 01:14:27 +00:00
virtual void terminate ( )
{
_run_m . lock ( ) ;
_run = false ;
_run_m . unlock ( ) ;
_phy . whack ( ) ;
}
// Begin private implementation methods
2015-04-11 00:07:06 +00:00
inline void phyOnDatagram ( PhySocket * sock , void * * uptr , const struct sockaddr * from , void * data , unsigned long len )
2015-04-10 01:14:27 +00:00
{
2015-05-22 21:52:23 +00:00
# ifdef ZT_BREAK_UDP
if ( OSUtils : : fileExists ( " /tmp/ZT_BREAK_UDP " ) )
return ;
# endif
if ( ( len > = 16 ) & & ( reinterpret_cast < const InetAddress * > ( from ) - > ipScope ( ) = = InetAddress : : IP_SCOPE_GLOBAL ) )
2015-05-22 01:33:52 +00:00
_lastDirectReceiveFromGlobal = OSUtils : : now ( ) ;
2015-04-11 00:07:06 +00:00
ZT1_ResultCode rc = _node - > processWirePacket (
OSUtils : : now ( ) ,
2015-09-23 20:49:56 +00:00
0 ,
2015-04-11 00:07:06 +00:00
( const struct sockaddr_storage * ) from , // Phy<> uses sockaddr_storage, so it'll always be that big
data ,
len ,
2015-04-11 02:08:49 +00:00
& _nextBackgroundTaskDeadline ) ;
2015-04-11 00:07:06 +00:00
if ( ZT1_ResultCode_isFatal ( rc ) ) {
char tmp [ 256 ] ;
2015-04-28 19:43:10 +00:00
Utils : : snprintf ( tmp , sizeof ( tmp ) , " fatal error code from processWirePacket: %d " , ( int ) rc ) ;
2015-04-11 00:07:06 +00:00
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = tmp ;
this - > terminate ( ) ;
}
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
{
2015-04-28 19:43:10 +00:00
if ( ! success )
return ;
2015-05-21 22:22:41 +00:00
// Outgoing TCP connections are always TCP fallback tunnel connections.
2015-05-22 22:46:06 +00:00
TcpConnection * tc = new TcpConnection ( ) ;
_tcpConnections . insert ( tc ) ;
2015-04-28 19:43:10 +00:00
tc - > type = TcpConnection : : TCP_TUNNEL_OUTGOING ;
2015-05-22 21:52:23 +00:00
tc - > shouldKeepAlive = true ;
2015-04-28 19:43:10 +00:00
tc - > parent = this ;
tc - > sock = sock ;
// from and parser are not used
tc - > messageSize = 0 ; // unused
tc - > lastActivity = OSUtils : : now ( ) ;
// HTTP stuff is not used
tc - > writeBuf = " " ;
* uptr = ( void * ) tc ;
// Send "hello" message
tc - > writeBuf . push_back ( ( char ) 0x17 ) ;
tc - > writeBuf . push_back ( ( char ) 0x03 ) ;
tc - > writeBuf . push_back ( ( char ) 0x03 ) ; // fake TLS 1.2 header
tc - > writeBuf . push_back ( ( char ) 0x00 ) ;
tc - > writeBuf . push_back ( ( char ) 0x04 ) ; // mlen == 4
tc - > writeBuf . push_back ( ( char ) ZEROTIER_ONE_VERSION_MAJOR ) ;
tc - > writeBuf . push_back ( ( char ) ZEROTIER_ONE_VERSION_MINOR ) ;
tc - > writeBuf . push_back ( ( char ) ( ( ZEROTIER_ONE_VERSION_REVISION > > 8 ) & 0xff ) ) ;
tc - > writeBuf . push_back ( ( char ) ( ZEROTIER_ONE_VERSION_REVISION & 0xff ) ) ;
2015-09-10 22:55:48 +00:00
_phy . setNotifyWritable ( sock , true ) ;
2015-05-22 21:52:23 +00:00
_tcpFallbackTunnel = tc ;
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
{
2015-05-21 22:22:41 +00:00
// Incoming TCP connections are HTTP JSON API requests.
2015-05-22 22:46:06 +00:00
TcpConnection * tc = new TcpConnection ( ) ;
_tcpConnections . insert ( tc ) ;
2015-04-28 19:43:10 +00:00
tc - > type = TcpConnection : : TCP_HTTP_INCOMING ;
tc - > shouldKeepAlive = true ;
tc - > parent = this ;
tc - > sock = sockN ;
tc - > from = from ;
http_parser_init ( & ( tc - > parser ) , HTTP_REQUEST ) ;
tc - > parser . data = ( void * ) tc ;
tc - > messageSize = 0 ;
tc - > lastActivity = OSUtils : : now ( ) ;
tc - > currentHeaderField = " " ;
tc - > currentHeaderValue = " " ;
tc - > url = " " ;
tc - > status = " " ;
tc - > headers . clear ( ) ;
tc - > body = " " ;
tc - > writeBuf = " " ;
* uptrN = ( void * ) tc ;
2015-04-10 01:14:27 +00:00
}
2015-04-11 00:07:06 +00:00
inline 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 ) {
if ( tc = = _tcpFallbackTunnel )
2015-05-22 01:33:52 +00:00
_tcpFallbackTunnel = ( TcpConnection * ) 0 ;
_tcpConnections . erase ( tc ) ;
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
}
2015-04-11 00:07:06 +00:00
inline void phyOnTcpData ( PhySocket * sock , void * * uptr , void * data , unsigned long len )
2015-04-10 01:14:27 +00:00
{
2015-04-28 19:43:10 +00:00
TcpConnection * tc = reinterpret_cast < TcpConnection * > ( * uptr ) ;
switch ( tc - > type ) {
2015-05-21 22:22:41 +00:00
2015-04-28 19:43:10 +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 ) ;
return ;
}
break ;
2015-05-21 22:22:41 +00:00
2015-04-28 19:43:10 +00:00
case TcpConnection : : TCP_TUNNEL_OUTGOING :
tc - > body . append ( ( const char * ) data , len ) ;
2015-05-22 21:52:23 +00:00
while ( tc - > body . length ( ) > = 5 ) {
2015-04-28 19:43:10 +00:00
const char * data = tc - > body . data ( ) ;
const unsigned long mlen = ( ( ( ( ( unsigned long ) data [ 3 ] ) & 0xff ) < < 8 ) | ( ( ( unsigned long ) data [ 4 ] ) & 0xff ) ) ;
if ( tc - > body . length ( ) > = ( mlen + 5 ) ) {
InetAddress from ;
unsigned long plen = mlen ; // payload length, modified if there's an IP header
2015-04-30 17:47:27 +00:00
data + = 5 ; // skip forward past pseudo-TLS junk and mlen
if ( plen = = 4 ) {
2015-04-28 19:43:10 +00:00
// Hello message, which isn't sent by proxy and would be ignored by client
2015-04-30 17:47:27 +00:00
} else if ( plen ) {
2015-04-28 19:43:10 +00:00
// 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 ;
2015-04-30 17:47:27 +00:00
} else {
_phy . close ( sock ) ;
return ;
2015-04-28 19:43:10 +00:00
}
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 ;
2015-04-30 17:47:27 +00:00
} else {
_phy . close ( sock ) ;
return ;
2015-04-28 19:43:10 +00:00
}
break ;
case 0 : // none/omitted
2015-04-30 17:47:27 +00:00
+ + data ;
- - plen ;
2015-04-28 19:43:10 +00:00
break ;
2015-04-30 17:47:27 +00:00
default : // invalid address type
2015-04-28 19:43:10 +00:00
_phy . close ( sock ) ;
return ;
}
2015-04-30 17:47:27 +00:00
2015-05-22 01:33:52 +00:00
if ( from ) {
ZT1_ResultCode rc = _node - > processWirePacket (
OSUtils : : now ( ) ,
2015-09-23 20:49:56 +00:00
0 ,
2015-05-22 01:33:52 +00:00
reinterpret_cast < struct sockaddr_storage * > ( & from ) ,
data ,
plen ,
& _nextBackgroundTaskDeadline ) ;
if ( ZT1_ResultCode_isFatal ( rc ) ) {
char tmp [ 256 ] ;
Utils : : snprintf ( tmp , sizeof ( tmp ) , " fatal error code from processWirePacket: %d " , ( int ) rc ) ;
Mutex : : Lock _l ( _termReason_m ) ;
_termReason = ONE_UNRECOVERABLE_ERROR ;
_fatalErrorMessage = tmp ;
this - > terminate ( ) ;
_phy . close ( sock ) ;
return ;
}
2015-04-28 19:43:10 +00:00
}
}
2015-05-21 22:22:41 +00:00
2015-04-28 19:43:10 +00:00
if ( tc - > body . length ( ) > ( mlen + 5 ) )
tc - > body = tc - > body . substr ( mlen + 5 ) ;
else tc - > body = " " ;
2015-05-22 21:52:23 +00:00
} else break ;
2015-04-28 19:43:10 +00:00
}
break ;
2015-05-21 22:22:41 +00:00
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 ) ;
2015-05-22 21:52:23 +00:00
Mutex : : Lock _l ( tc - > writeBuf_m ) ;
if ( tc - > writeBuf . length ( ) > 0 ) {
2015-09-10 22:55:48 +00:00
long sent = ( long ) _phy . streamSend ( sock , tc - > writeBuf . data ( ) , ( unsigned long ) tc - > writeBuf . length ( ) , true ) ;
2015-04-28 19:43:10 +00:00
if ( sent > 0 ) {
tc - > lastActivity = OSUtils : : now ( ) ;
2015-05-22 21:52:23 +00:00
if ( ( unsigned long ) sent > = ( unsigned long ) tc - > writeBuf . length ( ) ) {
2015-04-28 19:43:10 +00:00
tc - > writeBuf = " " ;
2015-09-10 22:55:48 +00:00
_phy . setNotifyWritable ( sock , false ) ;
2015-04-28 19:43:10 +00:00
if ( ! tc - > shouldKeepAlive )
2015-05-22 01:33:52 +00:00
_phy . close ( sock ) ; // will call close handler to delete from _tcpConnections
2015-05-22 21:52:23 +00:00
} else {
tc - > writeBuf = tc - > writeBuf . substr ( sent ) ;
}
2015-04-11 02:08:49 +00:00
}
2015-05-22 21:52:23 +00:00
} else {
2015-09-10 22:55:48 +00:00
_phy . setNotifyWritable ( sock , false ) ;
2015-05-22 21:52:23 +00:00
}
2015-04-10 01:14:27 +00:00
}
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 ) { }
inline void phyOnUnixWritable ( PhySocket * sock , void * * uptr ) { }
2015-09-10 20:18:57 +00:00
inline void phyOnSocketPairEndpointClose ( PhySocket * sock , void * * uptr ) { }
inline void phyOnSocketPairEndpointData ( PhySocket * sock , void * * uptr , void * data , unsigned long len ) { }
inline void phyOnSocketPairEndpointWritable ( PhySocket * sock , void * * uptr ) { }
2015-09-02 21:32:01 +00:00
2015-04-15 00:57:51 +00:00
inline int nodeVirtualNetworkConfigFunction ( uint64_t nwid , enum ZT1_VirtualNetworkConfigOperation op , const ZT1_VirtualNetworkConfig * nwc )
2015-04-10 01:14:27 +00:00
{
2015-04-15 00:57:51 +00:00
Mutex : : Lock _l ( _taps_m ) ;
std : : map < uint64_t , EthernetTap * > : : iterator t ( _taps . find ( nwid ) ) ;
switch ( op ) {
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_UP :
if ( t = = _taps . end ( ) ) {
try {
char friendlyName [ 1024 ] ;
Utils : : snprintf ( friendlyName , sizeof ( friendlyName ) , " ZeroTier One [%.16llx] " , nwid ) ;
t = _taps . insert ( std : : pair < uint64_t , EthernetTap * > ( nwid , new EthernetTap (
_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 ,
( void * ) this ) ) ) . first ;
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 ) {
fprintf ( tapFailLog , " %.16llx: %s " ZT_EOL_S , ( unsigned long long ) nwid , exc . what ( ) ) ;
fclose ( tapFailLog ) ;
}
# else
fprintf ( stderr , " ERROR: unable to configure virtual network port: %s " ZT_EOL_S , exc . what ( ) ) ;
# endif
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
}
}
// fall through...
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE :
if ( t ! = _taps . end ( ) ) {
t - > second - > setEnabled ( nwc - > enabled ! = 0 ) ;
std : : vector < InetAddress > & assignedIps = _tapAssignedIps [ nwid ] ;
std : : vector < InetAddress > newAssignedIps ;
for ( unsigned int i = 0 ; i < nwc - > assignedAddressCount ; + + i )
newAssignedIps . push_back ( InetAddress ( nwc - > assignedAddresses [ i ] ) ) ;
std : : sort ( newAssignedIps . begin ( ) , newAssignedIps . end ( ) ) ;
2015-06-29 17:21:28 +00:00
newAssignedIps . erase ( std : : unique ( newAssignedIps . begin ( ) , newAssignedIps . end ( ) ) , newAssignedIps . end ( ) ) ;
2015-04-15 00:57:51 +00:00
for ( std : : vector < InetAddress > : : iterator ip ( newAssignedIps . begin ( ) ) ; ip ! = newAssignedIps . end ( ) ; + + ip ) {
if ( ! std : : binary_search ( assignedIps . begin ( ) , assignedIps . end ( ) , * ip ) )
t - > second - > addIp ( * ip ) ;
}
for ( std : : vector < InetAddress > : : iterator ip ( assignedIps . begin ( ) ) ; ip ! = assignedIps . end ( ) ; + + ip ) {
if ( ! std : : binary_search ( newAssignedIps . begin ( ) , newAssignedIps . end ( ) , * ip ) )
t - > second - > removeIp ( * ip ) ;
}
assignedIps . swap ( newAssignedIps ) ;
2015-04-15 20:09:20 +00:00
} else {
return - 999 ; // tap init failed
2015-04-15 00:57:51 +00:00
}
break ;
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN :
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY :
if ( t ! = _taps . end ( ) ) {
2015-04-24 23:31:19 +00:00
# ifdef __WINDOWS__
std : : string winInstanceId ( t - > second - > instanceId ( ) ) ;
# endif
2015-04-15 00:57:51 +00:00
delete t - > second ;
_taps . erase ( t ) ;
_tapAssignedIps . erase ( nwid ) ;
2015-04-24 23:31:19 +00:00
# ifdef __WINDOWS__
if ( ( op = = ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY ) & & ( winInstanceId . length ( ) > 0 ) )
2015-07-30 18:31:38 +00:00
WindowsEthernetTap : : deletePersistentTapDevice ( winInstanceId . c_str ( ) ) ;
2015-04-24 23:31:19 +00:00
# endif
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
}
inline void nodeEventCallback ( enum ZT1_Event event , const void * metaData )
{
switch ( event ) {
case ZT1_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 ;
case ZT1_EVENT_TRACE : {
if ( metaData ) {
: : fprintf ( stderr , " %s " ZT_EOL_S , ( const char * ) metaData ) ;
: : fflush ( stderr ) ;
}
} break ;
default :
break ;
}
}
inline long nodeDataStoreGetFunction ( const char * name , void * buf , unsigned long bufSize , unsigned long readIndex , unsigned long * totalSize )
{
2015-04-11 00:07:06 +00:00
std : : string p ( _dataStorePrepPath ( name ) ) ;
if ( ! p . length ( ) )
return - 2 ;
2015-04-10 02:58:04 +00:00
FILE * f = fopen ( p . c_str ( ) , " rb " ) ;
if ( ! f )
return - 1 ;
if ( fseek ( f , 0 , SEEK_END ) ! = 0 ) {
fclose ( f ) ;
return - 2 ;
}
long ts = ftell ( f ) ;
if ( ts < 0 ) {
fclose ( f ) ;
return - 2 ;
}
* totalSize = ( unsigned long ) ts ;
if ( fseek ( f , ( long ) readIndex , SEEK_SET ) ! = 0 ) {
fclose ( f ) ;
return - 2 ;
}
long n = ( long ) fread ( buf , 1 , bufSize , f ) ;
fclose ( f ) ;
return n ;
2015-04-10 01:14:27 +00:00
}
inline int nodeDataStorePutFunction ( const char * name , const void * data , unsigned long len , int secure )
{
2015-04-11 00:07:06 +00:00
std : : string p ( _dataStorePrepPath ( name ) ) ;
if ( ! p . length ( ) )
return - 2 ;
2015-04-10 02:58:04 +00:00
if ( ! data ) {
OSUtils : : rm ( p . c_str ( ) ) ;
return 0 ;
}
FILE * f = fopen ( p . c_str ( ) , " wb " ) ;
if ( ! f )
return - 1 ;
2015-04-10 03:54:00 +00:00
if ( fwrite ( data , len , 1 , f ) = = 1 ) {
2015-04-10 02:58:04 +00:00
fclose ( f ) ;
2015-04-10 03:54:00 +00:00
if ( secure )
OSUtils : : lockDownFile ( p . c_str ( ) , false ) ;
2015-04-10 02:58:04 +00:00
return 0 ;
} else {
fclose ( f ) ;
OSUtils : : rm ( p . c_str ( ) ) ;
return - 1 ;
}
2015-04-10 01:14:27 +00:00
}
2015-05-21 22:58:26 +00:00
inline int nodeWirePacketSendFunction ( const struct sockaddr_storage * addr , const void * data , unsigned int len )
2015-04-10 01:14:27 +00:00
{
2015-05-22 01:33:52 +00:00
int result = - 1 ;
2015-04-10 01:14:27 +00:00
switch ( addr - > ss_family ) {
case AF_INET :
2015-05-22 21:52:23 +00:00
# ifdef ZT_BREAK_UDP
if ( ! OSUtils : : fileExists ( " /tmp/ZT_BREAK_UDP " ) ) {
# endif
if ( _v4UdpSocket )
result = ( ( _phy . udpSend ( _v4UdpSocket , ( const struct sockaddr * ) addr , data , len ) ! = 0 ) ? 0 : - 1 ) ;
# ifdef ZT_BREAK_UDP
}
# endif
2015-05-22 01:33:52 +00:00
2015-05-22 21:52:23 +00:00
# ifdef ZT1_TCP_FALLBACK_RELAY
// TCP fallback tunnel support
if ( ( len > = 16 ) & & ( reinterpret_cast < const InetAddress * > ( addr ) - > ipScope ( ) = = InetAddress : : IP_SCOPE_GLOBAL ) ) {
2015-05-22 01:33:52 +00:00
uint64_t now = OSUtils : : now ( ) ;
2015-05-22 21:52:23 +00:00
// Engage TCP tunnel fallback if we haven't received anything valid from a global
// IP address in ZT1_TCP_FALLBACK_AFTER milliseconds. If we do start getting
// valid direct traffic we'll stop using it and close the socket after a while.
if ( ( ( now - _lastDirectReceiveFromGlobal ) > ZT1_TCP_FALLBACK_AFTER ) & & ( ( now - _lastRestart ) > ZT1_TCP_FALLBACK_AFTER ) ) {
2015-05-22 01:33:52 +00:00
if ( _tcpFallbackTunnel ) {
2015-05-22 21:52:23 +00:00
Mutex : : Lock _l ( _tcpFallbackTunnel - > writeBuf_m ) ;
2015-05-22 01:33:52 +00:00
if ( ! _tcpFallbackTunnel - > writeBuf . length ( ) )
2015-09-10 22:55:48 +00:00
_phy . setNotifyWritable ( _tcpFallbackTunnel - > sock , true ) ;
2015-05-22 01:33:52 +00:00
unsigned long mlen = len + 7 ;
_tcpFallbackTunnel - > writeBuf . push_back ( ( char ) 0x17 ) ;
_tcpFallbackTunnel - > writeBuf . push_back ( ( char ) 0x03 ) ;
_tcpFallbackTunnel - > writeBuf . push_back ( ( char ) 0x03 ) ; // fake TLS 1.2 header
_tcpFallbackTunnel - > writeBuf . push_back ( ( char ) ( ( mlen > > 8 ) & 0xff ) ) ;
_tcpFallbackTunnel - > writeBuf . push_back ( ( char ) ( mlen & 0xff ) ) ;
_tcpFallbackTunnel - > writeBuf . push_back ( ( char ) 4 ) ; // IPv4
_tcpFallbackTunnel - > writeBuf . append ( reinterpret_cast < const char * > ( reinterpret_cast < const void * > ( & ( reinterpret_cast < const struct sockaddr_in * > ( addr ) - > sin_addr . s_addr ) ) ) , 4 ) ;
_tcpFallbackTunnel - > writeBuf . append ( reinterpret_cast < const char * > ( reinterpret_cast < const void * > ( & ( reinterpret_cast < const struct sockaddr_in * > ( addr ) - > sin_port ) ) ) , 2 ) ;
_tcpFallbackTunnel - > writeBuf . append ( ( const char * ) data , len ) ;
2015-05-22 21:52:23 +00:00
result = 0 ;
} else if ( ( ( now - _lastSendToGlobal ) < ZT1_TCP_FALLBACK_AFTER ) & & ( ( now - _lastSendToGlobal ) > ( ZT_PING_CHECK_INVERVAL / 2 ) ) ) {
2015-05-22 01:33:52 +00:00
std : : vector < InetAddress > tunnelIps ( _tcpFallbackResolver . get ( ) ) ;
if ( tunnelIps . empty ( ) ) {
if ( ! _tcpFallbackResolver . running ( ) )
_tcpFallbackResolver . resolveNow ( ) ;
} else {
bool connected = false ;
InetAddress addr ( tunnelIps [ ( unsigned long ) now % tunnelIps . size ( ) ] ) ;
addr . setPort ( ZT1_TCP_FALLBACK_RELAY_PORT ) ;
_phy . tcpConnect ( reinterpret_cast < const struct sockaddr * > ( & addr ) , connected ) ;
}
}
}
_lastSendToGlobal = now ;
}
2015-05-22 21:52:23 +00:00
# endif // ZT1_TCP_FALLBACK_RELAY
2015-05-22 01:33:52 +00:00
2015-04-10 01:14:27 +00:00
break ;
case AF_INET6 :
2015-05-22 21:52:23 +00:00
# ifdef ZT_BREAK_UDP
if ( ! OSUtils : : fileExists ( " /tmp/ZT_BREAK_UDP " ) ) {
# endif
2015-04-10 01:14:27 +00:00
if ( _v6UdpSocket )
2015-05-22 21:52:23 +00:00
result = ( ( _phy . udpSend ( _v6UdpSocket , ( const struct sockaddr * ) addr , data , len ) ! = 0 ) ? 0 : - 1 ) ;
# ifdef ZT_BREAK_UDP
}
# endif
2015-04-10 01:14:27 +00:00
break ;
2015-05-22 01:33:52 +00:00
default :
return - 1 ;
2015-04-10 01:14:27 +00:00
}
2015-05-22 01:33:52 +00:00
return result ;
2015-04-10 01:14:27 +00:00
}
inline void nodeVirtualNetworkFrameFunction ( uint64_t nwid , uint64_t sourceMac , uint64_t destMac , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )
{
2015-04-15 00:57:51 +00:00
Mutex : : Lock _l ( _taps_m ) ;
std : : map < uint64_t , EthernetTap * > : : const_iterator t ( _taps . find ( nwid ) ) ;
if ( t ! = _taps . end ( ) )
t - > second - > put ( MAC ( sourceMac ) , MAC ( destMac ) , etherType , data , len ) ;
}
inline void tapFrameHandler ( uint64_t nwid , const MAC & from , const MAC & to , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )
{
_node - > processVirtualNetworkFrame ( OSUtils : : now ( ) , nwid , from . toInt ( ) , to . toInt ( ) , etherType , vlanId , data , len , & _nextBackgroundTaskDeadline ) ;
2015-04-10 01:14:27 +00:00
}
2015-04-28 19:43:10 +00:00
inline void onHttpRequestToServer ( TcpConnection * tc )
2015-04-11 02:08:49 +00:00
{
char tmpn [ 256 ] ;
2015-04-11 02:36:29 +00:00
std : : string data ;
2015-04-14 01:12:45 +00:00
std : : string contentType ( " text/plain " ) ; // default if not changed in handleRequest()
2015-04-11 02:36:29 +00:00
unsigned int scode = 404 ;
2015-04-14 20:56:28 +00:00
try {
if ( _controlPlane )
2015-04-28 19:43:10 +00:00
scode = _controlPlane - > handleRequest ( tc - > from , tc - > parser . method , tc - > url , tc - > headers , tc - > body , data , contentType ) ;
2015-04-14 20:56:28 +00:00
else scode = 500 ;
} catch ( . . . ) {
scode = 500 ;
2015-04-11 02:36:29 +00:00
}
2015-04-11 02:08:49 +00:00
2015-04-14 01:12:45 +00:00
const char * scodestr ;
switch ( scode ) {
2015-04-14 01:43:33 +00:00
case 200 : scodestr = " OK " ; break ;
case 400 : scodestr = " Bad Request " ; break ;
case 401 : scodestr = " Unauthorized " ; break ;
case 403 : scodestr = " Forbidden " ; break ;
case 404 : scodestr = " Not Found " ; break ;
case 500 : scodestr = " Internal Server Error " ; break ;
case 501 : scodestr = " Not Implemented " ; break ;
case 503 : scodestr = " Service Unavailable " ; break ;
default : scodestr = " Error " ; break ;
2015-04-14 01:12:45 +00:00
}
Utils : : snprintf ( tmpn , sizeof ( tmpn ) , " HTTP/1.1 %.3u %s \r \n Cache-Control: no-cache \r \n Pragma: no-cache \r \n " , scode , scodestr ) ;
2015-05-22 21:52:23 +00:00
{
Mutex : : Lock _l ( tc - > writeBuf_m ) ;
tc - > writeBuf . assign ( tmpn ) ;
tc - > writeBuf . append ( " Content-Type: " ) ;
tc - > writeBuf . append ( contentType ) ;
Utils : : snprintf ( tmpn , sizeof ( tmpn ) , " \r \n Content-Length: %lu \r \n " , ( unsigned long ) data . length ( ) ) ;
tc - > writeBuf . append ( tmpn ) ;
if ( ! tc - > shouldKeepAlive )
tc - > writeBuf . append ( " Connection: close \r \n " ) ;
tc - > writeBuf . append ( " \r \n " ) ;
if ( tc - > parser . method ! = HTTP_HEAD )
tc - > writeBuf . append ( data ) ;
}
2015-04-28 19:43:10 +00:00
2015-09-10 22:55:48 +00:00
_phy . setNotifyWritable ( tc - > sock , true ) ;
2015-04-11 02:08:49 +00:00
}
2015-04-28 19:43:10 +00:00
inline void onHttpResponseFromClient ( TcpConnection * tc )
2015-04-11 02:08:49 +00:00
{
2015-04-28 19:43:10 +00:00
if ( ! tc - > shouldKeepAlive )
2015-05-22 01:33:52 +00:00
_phy . close ( tc - > sock ) ; // will call close handler, which deletes from _tcpConnections
2015-04-11 02:08:49 +00:00
}
2015-04-10 01:14:27 +00:00
private :
2015-04-11 00:07:06 +00:00
std : : string _dataStorePrepPath ( const char * name ) const
{
std : : string p ( _homePath ) ;
p . push_back ( ZT_PATH_SEPARATOR ) ;
char lastc = ( char ) 0 ;
for ( const char * n = name ; ( * n ) ; + + n ) {
if ( ( * n = = ' . ' ) & & ( lastc = = ' . ' ) )
return std : : string ( ) ; // don't allow ../../ stuff as a precaution
if ( * n = = ' / ' ) {
OSUtils : : mkdir ( p . c_str ( ) ) ;
p . push_back ( ZT_PATH_SEPARATOR ) ;
} else p . push_back ( * n ) ;
lastc = * n ;
}
return p ;
}
2015-04-10 02:58:04 +00:00
const std : : string _homePath ;
2015-05-21 22:22:41 +00:00
BackgroundResolver _tcpFallbackResolver ;
2015-05-17 22:51:07 +00:00
# ifdef ZT_ENABLE_NETWORK_CONTROLLER
SqliteNetworkController _controller ;
# endif
2015-04-15 21:42:26 +00:00
Phy < OneServiceImpl * > _phy ;
2015-04-10 01:14:27 +00:00
std : : string _overrideRootTopology ;
Node * _node ;
PhySocket * _v4UdpSocket ;
PhySocket * _v6UdpSocket ;
PhySocket * _v4TcpListenSocket ;
PhySocket * _v6TcpListenSocket ;
2015-04-14 01:12:45 +00:00
ControlPlane * _controlPlane ;
2015-05-22 01:33:52 +00:00
uint64_t _lastDirectReceiveFromGlobal ;
uint64_t _lastSendToGlobal ;
2015-05-22 21:52:23 +00:00
uint64_t _lastRestart ;
2015-04-15 20:09:20 +00:00
volatile uint64_t _nextBackgroundTaskDeadline ;
2015-04-11 02:08:49 +00:00
2015-04-14 22:55:03 +00:00
std : : map < uint64_t , EthernetTap * > _taps ;
2015-04-15 00:57:51 +00:00
std : : map < uint64_t , std : : vector < InetAddress > > _tapAssignedIps ; // ZeroTier assigned IPs, not user or dhcp assigned
2015-04-14 22:55:03 +00:00
Mutex _taps_m ;
2015-05-22 22:46:06 +00:00
std : : set < TcpConnection * > _tcpConnections ; // no mutex for this since it's done in the main loop thread only
2015-05-22 01:33:52 +00:00
TcpConnection * _tcpFallbackTunnel ;
2015-04-10 01:14:27 +00:00
ReasonForTermination _termReason ;
std : : string _fatalErrorMessage ;
Mutex _termReason_m ;
2015-07-06 23:32:34 +00:00
unsigned int _port ;
2015-07-28 21:32:02 +00:00
# ifdef ZT_USE_MINIUPNPC
UPNPClient _upnpClient ;
# endif
2015-04-10 01:14:27 +00:00
bool _run ;
Mutex _run_m ;
} ;
static int SnodeVirtualNetworkConfigFunction ( ZT1_Node * node , void * uptr , uint64_t nwid , enum ZT1_VirtualNetworkConfigOperation op , const ZT1_VirtualNetworkConfig * nwconf )
2015-04-15 21:42:26 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeVirtualNetworkConfigFunction ( nwid , op , nwconf ) ; }
2015-04-10 01:14:27 +00:00
static void SnodeEventCallback ( ZT1_Node * node , void * uptr , enum ZT1_Event event , const void * metaData )
2015-04-15 21:42:26 +00:00
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeEventCallback ( event , metaData ) ; }
2015-04-10 01:14:27 +00:00
static long SnodeDataStoreGetFunction ( ZT1_Node * node , void * uptr , const char * name , void * buf , unsigned long bufSize , unsigned long readIndex , unsigned long * totalSize )
2015-04-15 21:42:26 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeDataStoreGetFunction ( name , buf , bufSize , readIndex , totalSize ) ; }
2015-04-10 01:14:27 +00:00
static int SnodeDataStorePutFunction ( ZT1_Node * node , void * uptr , const char * name , const void * data , unsigned long len , int secure )
2015-04-15 21:42:26 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeDataStorePutFunction ( name , data , len , secure ) ; }
2015-09-23 20:49:56 +00:00
static int SnodeWirePacketSendFunction ( ZT1_Node * node , void * uptr , int localInterfaceId , const struct sockaddr_storage * addr , const void * data , unsigned int len )
2015-05-21 22:58:26 +00:00
{ return reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeWirePacketSendFunction ( addr , data , len ) ; }
2015-04-10 01:14:27 +00:00
static void SnodeVirtualNetworkFrameFunction ( ZT1_Node * node , void * uptr , uint64_t nwid , uint64_t sourceMac , uint64_t destMac , unsigned int etherType , unsigned int vlanId , const void * data , unsigned int len )
2015-04-15 21:42:26 +00:00
{ reinterpret_cast < OneServiceImpl * > ( uptr ) - > nodeVirtualNetworkFrameFunction ( nwid , sourceMac , destMac , etherType , vlanId , data , len ) ; }
2015-04-10 01:14:27 +00:00
2015-04-15 00:57:51 +00:00
static void StapFrameHandler ( void * uptr , 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 ;
tc - > url = " " ;
tc - > status = " " ;
tc - > headers . clear ( ) ;
tc - > body = " " ;
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 ;
}
static int ShttpOnStatus ( 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 - > status . append ( ptr , length ) ;
2015-04-11 02:08:49 +00:00
return 0 ;
}
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 ;
2015-04-28 19:43:10 +00:00
tc - > body . 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 ) ;
tc - > shouldKeepAlive = ( http_should_keep_alive ( parser ) ! = 0 ) ;
tc - > lastActivity = OSUtils : : now ( ) ;
if ( tc - > type = = TcpConnection : : TCP_HTTP_INCOMING ) {
tc - > parent - > onHttpRequestToServer ( tc ) ;
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
{
# ifdef __UNIX_LIKE__
# ifdef __APPLE__
// /Library/... on Apple
return std : : string ( " /Library/Application Support/ZeroTier/One " ) ;
# else
2015-05-17 23:06:29 +00:00
# ifdef __BSD__
// BSD likes /var/db instead of /var/lib
2015-04-10 02:58:04 +00:00
return std : : string ( " /var/db/zerotier-one " ) ;
# else
// Use /var/lib for Linux and other *nix
return std : : string ( " /var/lib/zerotier-one " ) ;
# endif
# endif
# else // not __UNIX_LIKE__
# ifdef __WINDOWS__
// Look up app data folder on Windows, e.g. C:\ProgramData\...
char buf [ 16384 ] ;
if ( SUCCEEDED ( SHGetFolderPathA ( NULL , CSIDL_COMMON_APPDATA , NULL , 0 , buf ) ) )
return ( std : : string ( buf ) + " \\ ZeroTier \\ One " ) ;
else return std : : string ( " C: \\ ZeroTier \\ One " ) ;
# else
2015-04-10 03:54:00 +00:00
return std : : string ( ) ; // UNKNOWN PLATFORM
2015-04-10 02:58:04 +00:00
# endif
# endif // __UNIX_LIKE__ or not...
}
2015-05-20 23:35:33 +00:00
std : : string OneService : : autoUpdateUrl ( )
{
# ifdef ZT_AUTO_UPDATE
/*
# if defined(__LINUX__) && ( defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__i386) )
if ( sizeof ( void * ) = = 8 )
return " http://download.zerotier.com/ZeroTierOneInstaller-linux-x64-LATEST.nfo " ;
else return " http://download.zerotier.com/ZeroTierOneInstaller-linux-x86-LATEST.nfo " ;
# endif
*/
# if defined(__APPLE__) && ( defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__i386) )
2015-05-21 02:38:49 +00:00
return " http://download.zerotier.com/update/mac_intel/ " ;
2015-05-20 23:35:33 +00:00
# endif
# ifdef __WINDOWS__
2015-05-21 02:38:49 +00:00
return " http://download.zerotier.com/update/win_intel/ " ;
2015-05-20 23:35:33 +00:00
# endif
# endif // ZT_AUTO_UPDATE
return std : : string ( ) ;
}
2015-05-17 22:51:07 +00:00
OneService * OneService : : newInstance ( const char * hp , unsigned int port , const char * overrideRootTopology ) { return new OneServiceImpl ( hp , port , overrideRootTopology ) ; }
2015-04-15 21:42:26 +00:00
OneService : : ~ OneService ( ) { }
2015-04-10 01:14:27 +00:00
} // namespace ZeroTier