@ -25,51 +25,39 @@
* LLC . Start here : http : //www.zerotier.com/
*/
# ifndef ZT_ETHERNETTAP_HPP
# define ZT_ETHERNETTAP_HPP
# ifndef ZT_WINDOWS ETHERNETTAP_HPP
# define ZT_WINDOWS ETHERNETTAP_HPP
# include <stdio.h>
# include <stdlib.h>
# include <map>
# include <list>
# include <vector>
# include <set>
# include <string>
# include <queue>
# include <stdexcept>
# include "Constants.hpp"
# include "InetAddress.hpp"
# include "MAC.hpp"
# include "EthernetTap.hpp"
# include "Mutex.hpp"
# include "MulticastGroup.hpp"
# include "Thread.hpp"
# include "Buffer.hpp"
# include "Array.hpp"
# ifdef __WINDOWS__
# include <WinSock2.h>
# include <Windows.h>
# endif
namespace ZeroTier {
class RuntimeEnvironment ;
/**
* System e thernet tap device
* Windows E thernet tap device using bundled ztTap driver
*/
class EthernetTap
class WindowsEthernetTap : public EthernetTap
{
public :
/**
* Construct a new TAP device
*
* Handler arguments : arg , from , to , etherType , data
* Open tap device , installing and creating one if it does not exist
*
* @ param renv Runtime environment
* @ param tag A tag used to persist tap identity at the OS layer ( e . g . nwid in hex for Windows or device name for * nix )
* @ param tag A tag ( presently the hex network ID ) used to identify persistent tap devices in the registry
* @ param mac MAC address of device
* @ param mtu MTU of device
* @ param desc If non - NULL , a description ( not used on all OSes )
@ -77,7 +65,7 @@ public:
* @ param arg First argument to handler function
* @ throws std : : runtime_error Unable to allocate device
*/
EthernetTap (
Windows EthernetTap(
const RuntimeEnvironment * renv ,
const char * tag ,
const MAC & mac ,
@ -86,120 +74,18 @@ public:
void * arg )
throw ( std : : runtime_error ) ;
/**
* Close tap and shut down thread
*
* This may block for a few seconds while thread exits .
*/
~ EthernetTap ( ) ;
/**
* Set the user display name for this connection
*
* This does nothing on platforms that don ' t have this concept .
*
* @ param dn User display name
*/
void setDisplayName ( const char * dn ) ;
/**
* @ return MAC address of this interface
*/
inline const MAC & mac ( ) const throw ( ) { return _mac ; }
/**
* @ return MTU of this interface
*/
inline unsigned int mtu ( ) const throw ( ) { return _mtu ; }
/**
* Add an IP to this interface
*
* @ param ip IP and netmask ( netmask stored in port field )
* @ return True if IP added successfully
*/
bool addIP ( const InetAddress & ip ) ;
/**
* Remove an IP from this interface
*
* Link - local IP addresses may not be able to be removed , depending on platform and type .
*
* @ param ip IP and netmask ( netmask stored in port field )
* @ return True if IP removed successfully
*/
bool removeIP ( const InetAddress & ip ) ;
/**
* @ return All IP addresses ( V4 and V6 ) assigned to this interface ( including link - local )
*/
std : : set < InetAddress > ips ( ) const ;
/**
* Set this tap ' s IP addresses to exactly this set of IPs
*
* New IPs are created , ones not in this list are removed .
*
* @ param ips IP addresses with netmask in port field
*/
inline void setIps ( const std : : set < InetAddress > & allIps )
{
for ( std : : set < InetAddress > : : iterator i ( allIps . begin ( ) ) ; i ! = allIps . end ( ) ; + + i )
addIP ( * i ) ;
std : : set < InetAddress > myIps ( ips ( ) ) ;
# ifdef __APPLE__
bool haveV6LinkLocal = false ;
for ( std : : set < InetAddress > : : iterator i ( myIps . begin ( ) ) ; i ! = myIps . end ( ) ; + + i ) {
if ( i - > isLinkLocal ( ) ) {
if ( i - > isV6 ( ) )
haveV6LinkLocal = true ;
} else if ( ! allIps . count ( * i ) )
removeIP ( * i ) ;
}
if ( ! haveV6LinkLocal )
addIP ( InetAddress : : makeIpv6LinkLocal ( _mac ) ) ;
# else
for ( std : : set < InetAddress > : : iterator i ( myIps . begin ( ) ) ; i ! = myIps . end ( ) ; + + i ) {
if ( ( ! i - > isLinkLocal ( ) ) & & ( ! allIps . count ( * i ) ) )
removeIP ( * i ) ;
}
# endif
}
virtual ~ WindowsEthernetTap ( ) ;
/**
* Put a frame , making it available to the OS for processing
*
* @ param from MAC address from which frame originated
* @ param to MAC address of destination ( typically MAC of tap itself )
* @ param etherType Ethernet protocol ID
* @ param data Frame payload
* @ param len Length of frame
*/
void put ( const MAC & from , const MAC & to , unsigned int etherType , const void * data , unsigned int len ) ;
/**
* @ return OS - specific device or connection name
*/
std : : string deviceName ( ) const ;
/**
* @ return OS - internal persistent device ID or empty string if not applicable to this platform or not persistent
*/
std : : string persistentId ( ) const ;
/**
* Fill or modify a set to contain multicast groups for this device
*
* This populates a set or , if already populated , modifies it to contain
* only multicast groups in which this device is interested .
*
* This should always include the blind wildcard MulticastGroup ( MAC of
* ff : ff : ff : ff : ff : ff and 0 ADI field ) .
*
* @ param groups Set to modify in place
* @ return True if set was changed since last call
*/
bool updateMulticastGroups ( std : : set < MulticastGroup > & groups ) ;
virtual void setEnabled ( bool en ) ;
virtual bool enabled ( ) const ;
virtual void setDisplayName ( const char * dn ) ;
virtual bool addIP ( const InetAddress & ip ) ;
virtual bool removeIP ( const InetAddress & ip ) ;
virtual std : : set < InetAddress > ips ( ) const ;
virtual void put ( const MAC & from , const MAC & to , unsigned int etherType , const void * data , unsigned int len ) ;
virtual std : : string deviceName ( ) const ;
virtual std : : string persistentId ( ) const ;
virtual bool updateMulticastGroups ( std : : set < MulticastGroup > & groups ) ;
/**
* Thread main method ; do not call elsewhere
@ -210,10 +96,6 @@ public:
/**
* Remove persistent tap device by device name
*
* This has no effect on platforms that do not have persistent taps .
* On platforms like Windows with persistent devices the device is
* uninstalled .
*
* @ param _r Runtime environment
* @ param pdev Device name as returned by persistentId ( ) while tap is running
* @ return True if a device was deleted
@ -223,10 +105,6 @@ public:
/**
* Clean persistent tap devices that are not in the supplied set
*
* This has no effect on platforms that do not have persistent taps .
* On platforms like Windows with persistent devices the device is
* uninstalled .
*
* @ param _r Runtime environment
* @ param exceptThese Devices to leave in place
* @ param alsoRemoveUnassociatedDevices If true , remove devices not associated with any network as well
@ -235,37 +113,23 @@ public:
static int cleanPersistentTapDevices ( const RuntimeEnvironment * _r , const std : : set < std : : string > & exceptThese , bool alsoRemoveUnassociatedDevices ) ;
private :
const MAC _mac ;
const unsigned int _mtu ;
const RuntimeEnvironment * _r ;
void ( * _handler ) ( void * , const MAC & , const MAC & , unsigned int , const Buffer < 4096 > & ) ;
void * _arg ;
Thread _thread ;
# ifdef __UNIX_LIKE__
char _dev [ 16 ] ;
int _fd ;
int _shutdownSignalPipe [ 2 ] ;
# endif
# ifdef __WINDOWS__
void _syncIpsWithRegistry ( const std : : set < InetAddress > & haveIps ) ;
HANDLE _tap ;
OVERLAPPED _tapOvlRead , _tapOvlWrite ;
char _tapReadBuf [ ZT_IF_MTU + 32 ] ;
HANDLE _injectSemaphore ;
GUID _deviceGuid ;
std : : string _myDevice InstanceId ; // NetCfgInstanceId, a GUID
std : : string _myDeviceInstanceIdPath ; // DeviceInstanceID, another kind of "instance ID"
std : : string _netCfgInstanceId ; // NetCfgInstanceId, a GUID
std : : string _deviceInstanceId ; // DeviceInstanceID, another kind of "instance ID"
std : : queue < std : : pair < Array < char , ZT_IF_MTU + 32 > , unsigned int > > _injectPending ;
Mutex _injectPending_m ;
volatile bool _run ;
volatile bool _initialized ;
# endif
volatile bool _enabled ;
} ;
} // namespace ZeroTier