@ -328,28 +328,12 @@ OSXEthernetTap::OSXEthernetTap(
_fd ( 0 ) ,
_fd ( 0 ) ,
_enabled ( true )
_enabled ( true )
{
{
char devpath [ 64 ] , ethaddr [ 64 ] , mtustr [ 16 ] , tmp [ 4096 ] ;
char devpath [ 64 ] , ethaddr [ 64 ] , mtustr [ 32 ] , metstr [ 32 ] ;
struct stat stattmp ;
struct stat stattmp ;
Mutex : : Lock _l ( __tapCreateLock ) ; // create only one tap at a time, globally
Mutex : : Lock _l ( __tapCreateLock ) ; // create only one tap at a time, globally
if ( mtu > 2800 )
if ( mtu > 2800 )
throw std : : runtime_error ( " max tap MTU is 2800 " ) ;
throw std : : runtime_error ( " max tap MTU is 2800 " ) ;
// Check for existence of ZT tap devices, try to load module if not there
const char * kextload = UNIX_COMMANDS [ ZT_MAC_KEXTLOAD_COMMAND ] ;
if ( ( stat ( " /dev/zt0 " , & stattmp ) ) & & ( kextload ) ) {
strcpy ( tmp , _r - > homePath . c_str ( ) ) ;
long kextpid = ( long ) vfork ( ) ;
if ( kextpid = = 0 ) {
chdir ( tmp ) ;
execl ( kextload , kextload , " -q " , " -repository " , tmp , " tap.kext " , ( const char * ) 0 ) ;
_exit ( - 1 ) ;
} else if ( kextpid > 0 ) {
int exitcode = - 1 ;
waitpid ( kextpid , & exitcode , 0 ) ;
usleep ( 500 ) ;
} else throw std : : runtime_error ( " unable to create subprocess with fork() " ) ;
}
if ( stat ( " /dev/zt0 " , & stattmp ) )
if ( stat ( " /dev/zt0 " , & stattmp ) )
throw std : : runtime_error ( " /dev/zt# tap devices do not exist and unable to load kernel extension " ) ;
throw std : : runtime_error ( " /dev/zt# tap devices do not exist and unable to load kernel extension " ) ;
@ -390,22 +374,17 @@ OSXEthernetTap::OSXEthernetTap(
throw std : : runtime_error ( " unable to set flags on file descriptor for TAP device " ) ;
throw std : : runtime_error ( " unable to set flags on file descriptor for TAP device " ) ;
}
}
const char * ifconfig = UNIX_COMMANDS [ ZT_UNIX_IFCONFIG_COMMAND ] ;
if ( ! ifconfig ) {
: : close ( _fd ) ;
throw std : : runtime_error ( " unable to find 'ifconfig' command on system " ) ;
}
// Configure MAC address and MTU, bring interface up
// Configure MAC address and MTU, bring interface up
Utils : : snprintf ( ethaddr , sizeof ( ethaddr ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( int ) mac [ 0 ] , ( int ) mac [ 1 ] , ( int ) mac [ 2 ] , ( int ) mac [ 3 ] , ( int ) mac [ 4 ] , ( int ) mac [ 5 ] ) ;
Utils : : snprintf ( ethaddr , sizeof ( ethaddr ) , " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x " , ( int ) mac [ 0 ] , ( int ) mac [ 1 ] , ( int ) mac [ 2 ] , ( int ) mac [ 3 ] , ( int ) mac [ 4 ] , ( int ) mac [ 5 ] ) ;
Utils : : snprintf ( mtustr , sizeof ( mtustr ) , " %u " , mtu ) ;
Utils : : snprintf ( mtustr , sizeof ( mtustr ) , " %u " , _mtu ) ;
long cpid ;
Utils : : snprintf ( metstr , sizeof ( metstr ) , " %u " , _metric )
if ( ( cpid = ( long ) vfork ( ) ) = = 0 ) {
long cpid = ( long ) vfork ( ) ;
execl ( ifconfig , ifconfig , _dev . c_str ( ) , " lladdr " , ethaddr , " mtu " , mtustr , " up " , ( const char * ) 0 ) ;
if ( cpid = = 0 ) {
_exit ( - 1 ) ;
: : execl ( " /sbin/ifconfig " , " /sbin/ifconfig " , _dev . c_str ( ) , " lladdr " , ethaddr , " mtu " , mtustr , " metric " , metstr , " up " , ( const char * ) 0 ) ;
} else {
: : _exit ( - 1 ) ;
} else if ( cpid > 0 ) {
int exitcode = - 1 ;
int exitcode = - 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
: : waitpid ( cpid , & exitcode , 0 ) ;
if ( exitcode ) {
if ( exitcode ) {
: : close ( _fd ) ;
: : close ( _fd ) ;
throw std : : runtime_error ( " ifconfig failure setting link-layer address and activating tap interface " ) ;
throw std : : runtime_error ( " ifconfig failure setting link-layer address and activating tap interface " ) ;
@ -420,10 +399,6 @@ OSXEthernetTap::OSXEthernetTap(
: : pipe ( _shutdownSignalPipe ) ;
: : pipe ( _shutdownSignalPipe ) ;
_thread = Thread : : start ( this ) ;
_thread = Thread : : start ( this ) ;
EthernetTap_instances_m . lock ( ) ;
+ + EthernetTap_instances ;
EthernetTap_instances_m . unlock ( ) ;
}
}
OSXEthernetTap : : ~ OSXEthernetTap ( )
OSXEthernetTap : : ~ OSXEthernetTap ( )
@ -433,27 +408,6 @@ OSXEthernetTap::~OSXEthernetTap()
: : close ( _fd ) ;
: : close ( _fd ) ;
: : close ( _shutdownSignalPipe [ 0 ] ) ;
: : close ( _shutdownSignalPipe [ 0 ] ) ;
: : close ( _shutdownSignalPipe [ 1 ] ) ;
: : close ( _shutdownSignalPipe [ 1 ] ) ;
EthernetTap_instances_m . lock ( ) ;
int instances = - - EthernetTap_instances ;
EthernetTap_instances_m . unlock ( ) ;
if ( instances < = 0 ) {
// Unload OSX kernel extension on the deletion of the last EthernetTap
// instance.
const char * kextunload = UNIX_COMMANDS [ ZT_MAC_KEXTUNLOAD_COMMAND ] ;
if ( kextunload ) {
char tmp [ 4096 ] ;
sprintf ( tmp , " %s/tap.kext " , _r - > homePath . c_str ( ) ) ;
long kextpid = ( long ) vfork ( ) ;
if ( kextpid = = 0 ) {
execl ( kextunload , kextunload , tmp , ( const char * ) 0 ) ;
_exit ( - 1 ) ;
} else if ( kextpid > 0 ) {
int exitcode = - 1 ;
waitpid ( kextpid , & exitcode , 0 ) ;
}
}
}
}
}
void OSXEthernetTap : : setEnabled ( bool en )
void OSXEthernetTap : : setEnabled ( bool en )
@ -469,14 +423,11 @@ bool OSXEthernetTap::enabled() const
static bool ___removeIp ( const std : : string & _dev , const InetAddress & ip )
static bool ___removeIp ( const std : : string & _dev , const InetAddress & ip )
{
{
const char * ifconfig = UNIX_COMMANDS [ ZT_UNIX_IFCONFIG_COMMAND ] ;
long cpid = ( long ) vfork ( ) ;
if ( ! ifconfig )
if ( cpid = = 0 ) {
return false ;
execl ( " /sbin/ifconfig " , " /sbin/ifconfig " , _dev . c_str ( ) , " inet " , ip . toIpString ( ) . c_str ( ) , " -alias " , ( const char * ) 0 ) ;
long cpid ;
if ( ( cpid = ( long ) vfork ( ) ) = = 0 ) {
execl ( ifconfig , ifconfig , _dev . c_str ( ) , " inet " , ip . toIpString ( ) . c_str ( ) , " -alias " , ( const char * ) 0 ) ;
_exit ( - 1 ) ;
_exit ( - 1 ) ;
} else {
} else ( cpid > 0 ) {
int exitcode = - 1 ;
int exitcode = - 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
waitpid ( cpid , & exitcode , 0 ) ;
return ( exitcode = = 0 ) ;
return ( exitcode = = 0 ) ;
@ -486,12 +437,6 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
bool OSXEthernetTap : : addIP ( const InetAddress & ip )
bool OSXEthernetTap : : addIP ( const InetAddress & ip )
{
{
const char * ifconfig = UNIX_COMMANDS [ ZT_UNIX_IFCONFIG_COMMAND ] ;
if ( ! ifconfig ) {
LOG ( " ERROR: could not configure IP address for %s: unable to find 'ifconfig' command on system (checked /sbin, /bin, /usr/sbin, /usr/bin) " , _dev . c_str ( ) ) ;
return false ;
}
if ( ! ip )
if ( ! ip )
return false ;
return false ;
@ -510,16 +455,15 @@ bool OSXEthernetTap::addIP(const InetAddress &ip)
}
}
}
}
long cpid ;
long cpid = ( long ) vfork ( ) ;
if ( ( cpid = ( long ) vfork ( ) ) = = 0 ) {
if ( cpid = = 0 ) {
execl ( ifconfig , ifconfig , _dev . c_str ( ) , ip . isV4 ( ) ? " inet " : " inet6 " , ip . toString ( ) . c_str ( ) , " alias " , ( const char * ) 0 ) ;
: : execl ( " /sbin/ ifconfig" , " /sbin/ ifconfig" , _dev . c_str ( ) , ip . isV4 ( ) ? " inet " : " inet6 " , ip . toString ( ) . c_str ( ) , " alias " , ( const char * ) 0 ) ;
_exit ( - 1 ) ;
: : _exit ( - 1 ) ;
} else {
} else if ( cpid > 0 ) {
int exitcode = - 1 ;
int exitcode = - 1 ;
waitpid ( cpid , & exitcode , 0 ) ;
: : waitpid ( cpid , & exitcode , 0 ) ;
return ( exitcode = = 0 ) ;
return ( exitcode = = 0 ) ;
}
}
return false ;
return false ;
}
}
@ -569,22 +513,14 @@ std::set<InetAddress> OSXEthernetTap::ips() const
void OSXEthernetTap : : put ( const MAC & from , const MAC & to , unsigned int etherType , const void * data , unsigned int len )
void OSXEthernetTap : : put ( const MAC & from , const MAC & to , unsigned int etherType , const void * data , unsigned int len )
{
{
char putBuf [ 4096 + 14 ] ;
char putBuf [ 4096 ] ;
if ( ( _fd > 0 ) & & ( len < = _mtu ) ) {
if ( ( _fd > 0 ) & & ( len < = _mtu ) & & ( _enabled ) ) {
to . copyTo ( putBuf , 6 ) ;
to . copyTo ( putBuf , 6 ) ;
from . copyTo ( putBuf + 6 , 6 ) ;
from . copyTo ( putBuf + 6 , 6 ) ;
* ( ( uint16_t * ) ( putBuf + 12 ) ) = htons ( ( uint16_t ) etherType ) ;
* ( ( uint16_t * ) ( putBuf + 12 ) ) = htons ( ( uint16_t ) etherType ) ;
memcpy ( putBuf + 14 , data , len ) ;
memcpy ( putBuf + 14 , data , len ) ;
len + = 14 ;
len + = 14 ;
: : write ( _fd , putBuf , len ) ;
int n = : : write ( _fd , putBuf , len ) ;
if ( n < = 0 ) {
LOG ( " error writing packet to Ethernet tap device: %s " , strerror ( errno ) ) ;
} else if ( n ! = ( int ) len ) {
// Saw this gremlin once, so log it if we see it again... OSX tap
// or something seems to have goofy issues with certain MTUs.
LOG ( " ERROR: write underrun: %s tap write() wrote %d of %u bytes of frame " , _dev . c_str ( ) , n , len ) ;
}
}
}
}
}
@ -669,10 +605,8 @@ void OSXEthernetTap::threadMain()
if ( FD_ISSET ( _fd , & readfds ) ) {
if ( FD_ISSET ( _fd , & readfds ) ) {
n = ( int ) : : read ( _fd , getBuf + r , sizeof ( getBuf ) - r ) ;
n = ( int ) : : read ( _fd , getBuf + r , sizeof ( getBuf ) - r ) ;
if ( n < 0 ) {
if ( n < 0 ) {
if ( ( errno ! = EINTR ) & & ( errno ! = ETIMEDOUT ) ) {
if ( ( errno ! = EINTR ) & & ( errno ! = ETIMEDOUT ) )
TRACE ( " unexpected error reading from tap: %s " , strerror ( errno ) ) ;
break ;
break ;
}
} else {
} else {
// Some tap drivers like to send the ethernet frame and the
// Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating
// payload in two chunks, so handle that by accumulating
@ -681,13 +615,15 @@ void OSXEthernetTap::threadMain()
if ( r > 14 ) {
if ( r > 14 ) {
if ( r > ( ( int ) _mtu + 14 ) ) // sanity check for weird TAP behavior on some platforms
if ( r > ( ( int ) _mtu + 14 ) ) // sanity check for weird TAP behavior on some platforms
r = _mtu + 14 ;
r = _mtu + 14 ;
to . setTo ( getBuf , 6 ) ;
from . setTo ( getBuf + 6 , 6 ) ;
if ( _enabled ) {
unsigned int etherType = ntohs ( ( ( const uint16_t * ) getBuf ) [ 6 ] ) ;
to . setTo ( getBuf , 6 ) ;
if ( etherType ! = 0x8100 ) { // VLAN tagged frames are not supported!
from . setTo ( getBuf + 6 , 6 ) ;
unsigned int etherType = ntohs ( ( ( const uint16_t * ) getBuf ) [ 6 ] ) ;
data . copyFrom ( getBuf + 14 , ( unsigned int ) r - 14 ) ;
data . copyFrom ( getBuf + 14 , ( unsigned int ) r - 14 ) ;
_handler ( _arg , from , to , etherType , data ) ;
_handler ( _arg , from , to , etherType , data ) ;
}
}
r = 0 ;
r = 0 ;
}
}
}
}