2013-07-04 16:56:19 -04:00
/*
2015-02-17 13:11:34 -08:00
* ZeroTier One - Network Virtualization Everywhere
2016-01-12 14:04:55 -08:00
* Copyright ( C ) 2011 - 2016 ZeroTier , Inc . https : //www.zerotier.com/
2013-07-04 16:56:19 -04:00
*
* 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/>.
*/
2013-12-06 16:49:20 -08:00
# ifndef ZT_NETWORK_HPP
# define ZT_NETWORK_HPP
2013-07-04 16:56:19 -04:00
2013-09-11 15:09:53 -04:00
# include <stdint.h>
2015-04-06 15:47:57 -07:00
# include "../include/ZeroTierOne.h"
2013-07-04 16:56:19 -04:00
# include <string>
2013-07-29 13:56:20 -04:00
# include <map>
2013-07-04 16:56:19 -04:00
# include <vector>
2013-09-11 16:08:31 -04:00
# include <algorithm>
2013-07-04 16:56:19 -04:00
# include <stdexcept>
2013-07-29 13:56:20 -04:00
# include "Constants.hpp"
2013-10-18 12:01:48 -04:00
# include "NonCopyable.hpp"
2015-09-04 13:42:19 -07:00
# include "Hashtable.hpp"
2013-07-04 16:56:19 -04:00
# include "Address.hpp"
# include "Mutex.hpp"
# include "SharedPtr.hpp"
# include "AtomicCounter.hpp"
# include "MulticastGroup.hpp"
2013-07-10 17:24:27 -04:00
# include "MAC.hpp"
2013-07-29 13:56:20 -04:00
# include "Dictionary.hpp"
2014-09-24 14:02:16 -07:00
# include "Multicaster.hpp"
2016-08-05 15:02:01 -07:00
# include "Membership.hpp"
2013-10-18 12:01:48 -04:00
# include "NetworkConfig.hpp"
2013-10-07 15:29:03 -04:00
# include "CertificateOfMembership.hpp"
2013-07-04 16:56:19 -04:00
2016-09-27 11:33:48 -07:00
# define ZT_NETWORK_MAX_INCOMING_UPDATES 3
# define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
2013-07-04 16:56:19 -04:00
namespace ZeroTier {
2013-07-29 13:56:20 -04:00
class RuntimeEnvironment ;
2015-10-01 11:11:52 -07:00
class Peer ;
2013-07-04 16:56:19 -04:00
/**
2013-07-27 16:20:08 -04:00
* A virtual LAN
2013-07-04 16:56:19 -04:00
*/
2013-07-09 14:06:55 -04:00
class Network : NonCopyable
2013-07-04 16:56:19 -04:00
{
friend class SharedPtr < Network > ;
2013-09-04 09:27:56 -04:00
2015-04-01 19:09:18 -07:00
public :
2013-09-04 09:27:56 -04:00
/**
2015-04-15 13:09:20 -07:00
* Broadcast multicast group : ff : ff : ff : ff : ff : ff / 0
*/
static const MulticastGroup BROADCAST ;
2016-09-23 16:08:38 -07:00
/**
* Compute primary controller device ID from network ID
*/
static inline Address controllerFor ( uint64_t nwid ) throw ( ) { return Address ( nwid > > 24 ) ; }
2015-04-15 13:09:20 -07:00
/**
* Construct a new network
*
* Note that init ( ) should be called immediately after the network is
* constructed to actually configure the port .
*
2013-10-18 12:01:48 -04:00
* @ param renv Runtime environment
2015-04-01 19:09:18 -07:00
* @ param nwid Network ID
2016-01-12 11:04:35 -08:00
* @ param uptr Arbitrary pointer used by externally - facing API ( for user use )
2013-09-04 09:27:56 -04:00
*/
2016-01-12 11:04:35 -08:00
Network ( const RuntimeEnvironment * renv , uint64_t nwid , void * uptr ) ;
2015-04-01 19:09:18 -07:00
~ Network ( ) ;
2013-07-29 17:11:00 -04:00
2016-09-23 16:08:38 -07:00
inline uint64_t id ( ) const { return _id ; }
inline Address controller ( ) const { return Address ( _id > > 24 ) ; }
inline bool multicastEnabled ( ) const { return ( _config . multicastLimit > 0 ) ; }
inline bool hasConfig ( ) const { return ( _config ) ; }
inline uint64_t lastConfigUpdate ( ) const throw ( ) { return _lastConfigUpdate ; }
inline ZT_VirtualNetworkStatus status ( ) const { Mutex : : Lock _l ( _lock ) ; return _status ( ) ; }
inline const NetworkConfig & config ( ) const { return _config ; }
inline const MAC & mac ( ) const { return _mac ; }
2016-08-04 13:01:14 -07:00
/**
* Apply filters to an outgoing packet
*
* This applies filters from our network config and , if that doesn ' t match ,
2016-08-31 16:50:22 -07:00
* our capabilities in ascending order of capability ID . Additional actions
2016-09-23 16:08:38 -07:00
* such as TEE may be taken , and credentials may be pushed , so this is not
* side - effect - free . It ' s basically step one in sending something over VL2 .
2016-08-04 13:01:14 -07:00
*
2016-09-23 16:08:38 -07:00
* @ param noTee If true , do not TEE anything anywhere ( for two - pass filtering as done with multicast and bridging )
2016-08-04 13:01:14 -07:00
* @ param ztSource Source ZeroTier address
* @ param ztDest Destination ZeroTier address
* @ param macSource Ethernet layer source address
* @ param macDest Ethernet layer destination address
* @ param frameData Ethernet frame data
* @ param frameLen Ethernet frame payload length
* @ param etherType 16 - bit ethernet type ID
* @ param vlanId 16 - bit VLAN ID
2016-08-31 16:50:22 -07:00
* @ return True if packet should be sent , false if dropped or redirected
2016-08-04 13:01:14 -07:00
*/
bool filterOutgoingPacket (
2016-08-31 16:50:22 -07:00
const bool noTee ,
2016-08-04 13:01:14 -07:00
const Address & ztSource ,
const Address & ztDest ,
const MAC & macSource ,
const MAC & macDest ,
const uint8_t * frameData ,
const unsigned int frameLen ,
const unsigned int etherType ,
const unsigned int vlanId ) ;
/**
* Apply filters to an incoming packet
*
* This applies filters from our network config and , if that doesn ' t match ,
* the peer ' s capabilities in ascending order of capability ID . If there is
* a match certain actions may be taken such as sending a copy of the packet
* to a TEE or REDIRECT target .
*
2016-08-05 15:02:01 -07:00
* @ param sourcePeer Source Peer
2016-08-04 13:01:14 -07:00
* @ param ztDest Destination ZeroTier address
* @ param macSource Ethernet layer source address
* @ param macDest Ethernet layer destination address
* @ param frameData Ethernet frame data
* @ param frameLen Ethernet frame payload length
* @ param etherType 16 - bit ethernet type ID
* @ param vlanId 16 - bit VLAN ID
2016-08-29 15:54:06 -07:00
* @ return 0 = = drop , 1 = = accept , 2 = = accept even if bridged
2016-08-04 13:01:14 -07:00
*/
2016-08-29 15:54:06 -07:00
int filterIncomingPacket (
2016-08-05 15:02:01 -07:00
const SharedPtr < Peer > & sourcePeer ,
2016-08-04 13:01:14 -07:00
const Address & ztDest ,
const MAC & macSource ,
const MAC & macDest ,
const uint8_t * frameData ,
const unsigned int frameLen ,
const unsigned int etherType ,
const unsigned int vlanId ) ;
2013-07-04 16:56:19 -04:00
/**
2016-09-23 16:08:38 -07:00
* Check whether we are subscribed to a multicast group
*
2014-10-09 18:32:05 -07:00
* @ param mg Multicast group
2016-09-23 16:08:38 -07:00
* @ param includeBridgedGroups If true , also check groups we ' ve learned via bridging
2014-10-09 18:32:05 -07:00
* @ return True if this network endpoint / peer is a member
*/
2015-04-06 19:41:55 -07:00
bool subscribedToMulticastGroup ( const MulticastGroup & mg , bool includeBridgedGroups ) const ;
2014-10-09 18:32:05 -07:00
2015-04-06 18:27:24 -07:00
/**
* Subscribe to a multicast group
*
* @ param mg New multicast group
*/
void multicastSubscribe ( const MulticastGroup & mg ) ;
/**
* Unsubscribe from a multicast group
*
* @ param mg Multicast group
*/
void multicastUnsubscribe ( const MulticastGroup & mg ) ;
2016-08-09 13:14:38 -07:00
/**
* Handle an inbound network config chunk
*
2016-09-27 11:33:48 -07:00
* This is called from IncomingPacket to handle incoming network config
* chunks via OK ( NETWORK_CONFIG_REQUEST ) or NETWORK_CONFIG . It verifies
* each chunk and once assembled applies the configuration .
2016-08-09 13:14:38 -07:00
*
2016-09-27 11:33:48 -07:00
* @ param chunk Packet containing chunk
* @ param ptr Index of chunk and related fields in packet
* @ return Update ID if update was fully assembled and accepted or 0 otherwise
2016-08-09 13:14:38 -07:00
*/
2016-09-27 11:33:48 -07:00
uint64_t handleConfigChunk ( const Packet & chunk , unsigned int ptr ) ;
2016-08-09 13:14:38 -07:00
2014-01-27 23:13:36 -08:00
/**
2015-04-15 15:12:09 -07:00
* Set netconf failure to ' access denied ' - - called in IncomingPacket when controller reports this
2013-07-29 13:56:20 -04:00
*/
2014-01-27 23:13:36 -08:00
inline void setAccessDenied ( )
{
Mutex : : Lock _l ( _lock ) ;
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED ;
}
/**
2016-09-23 16:08:38 -07:00
* Set netconf failure to ' not found ' - - called by IncomingPacket when controller reports this
2014-01-27 23:13:36 -08:00
*/
inline void setNotFound ( )
{
Mutex : : Lock _l ( _lock ) ;
_netconfFailure = NETCONF_FAILURE_NOT_FOUND ;
}
2013-07-29 13:56:20 -04:00
/**
* Causes this network to request an updated configuration from its master node now
*/
void requestConfiguration ( ) ;
2013-07-29 17:11:00 -04:00
/**
2016-09-20 21:21:34 -07:00
* Determine whether this peer is permitted to communicate on this network
2016-09-09 09:32:00 -07:00
*/
2016-09-27 13:49:43 -07:00
bool gate ( const SharedPtr < Peer > & peer ) ;
2016-09-09 09:32:00 -07:00
2013-07-29 17:11:00 -04:00
/**
2016-09-23 16:08:38 -07:00
* Do periodic cleanup and housekeeping tasks
2013-07-29 17:11:00 -04:00
*/
void clean ( ) ;
2016-09-07 15:15:52 -07:00
/**
2016-09-08 19:48:05 -07:00
* Push state to members such as multicast group memberships and latest COM ( if needed )
2016-09-07 15:15:52 -07:00
*/
2016-09-09 11:36:10 -07:00
inline void sendUpdatesToMembers ( )
2016-09-07 15:15:52 -07:00
{
Mutex : : Lock _l ( _lock ) ;
2016-09-09 11:36:10 -07:00
_sendUpdatesToMembers ( ( const MulticastGroup * ) 0 ) ;
2016-09-07 15:15:52 -07:00
}
2014-06-10 17:18:59 -07:00
/**
2014-09-26 12:23:43 -07:00
* Find the node on this network that has this MAC behind it ( if any )
*
2014-06-10 17:18:59 -07:00
* @ param mac MAC address
2014-09-26 12:23:43 -07:00
* @ return ZeroTier address of bridge to this MAC
2014-06-10 17:18:59 -07:00
*/
inline Address findBridgeTo ( const MAC & mac ) const
{
Mutex : : Lock _l ( _lock ) ;
2015-09-04 13:53:48 -07:00
const Address * const br = _remoteBridgeRoutes . get ( mac ) ;
2016-09-09 11:36:10 -07:00
return ( ( br ) ? * br : Address ( ) ) ;
2014-06-10 17:18:59 -07:00
}
/**
* Set a bridge route
*
* @ param mac MAC address of destination
* @ param addr Bridge this MAC is reachable behind
*/
void learnBridgeRoute ( const MAC & mac , const Address & addr ) ;
2014-06-13 14:06:34 -07:00
/**
* Learn a multicast group that is bridged to our tap device
*
* @ param mg Multicast group
2014-06-26 18:13:48 -07:00
* @ param now Current time
2014-06-13 14:06:34 -07:00
*/
2015-04-06 18:27:24 -07:00
void learnBridgedMulticastGroup ( const MulticastGroup & mg , uint64_t now ) ;
2014-06-13 14:06:34 -07:00
2016-08-08 17:33:26 -07:00
/**
2016-09-23 16:08:38 -07:00
* Validate a credential and learn it if it passes certificate and other checks
2016-08-08 17:33:26 -07:00
*/
2016-09-23 16:08:38 -07:00
Membership : : AddCredentialResult addCredential ( const CertificateOfMembership & com ) ;
2016-08-08 17:33:26 -07:00
/**
2016-09-23 16:08:38 -07:00
* Validate a credential and learn it if it passes certificate and other checks
2016-08-08 17:33:26 -07:00
*/
2016-09-23 16:08:38 -07:00
inline Membership : : AddCredentialResult addCredential ( const Capability & cap )
2016-08-08 17:33:26 -07:00
{
if ( cap . networkId ( ) ! = _id )
2016-09-23 16:08:38 -07:00
return Membership : : ADD_REJECTED ;
2016-08-08 17:33:26 -07:00
Mutex : : Lock _l ( _lock ) ;
2016-09-23 16:08:38 -07:00
return _membership ( cap . issuedTo ( ) ) . addCredential ( RR , _config , cap ) ;
2016-08-08 17:33:26 -07:00
}
/**
2016-09-23 16:08:38 -07:00
* Validate a credential and learn it if it passes certificate and other checks
2016-08-08 17:33:26 -07:00
*/
2016-09-23 16:08:38 -07:00
inline Membership : : AddCredentialResult addCredential ( const Tag & tag )
2016-08-08 17:33:26 -07:00
{
if ( tag . networkId ( ) ! = _id )
2016-09-23 16:08:38 -07:00
return Membership : : ADD_REJECTED ;
2016-08-08 17:33:26 -07:00
Mutex : : Lock _l ( _lock ) ;
2016-09-23 16:08:38 -07:00
return _membership ( tag . issuedTo ( ) ) . addCredential ( RR , _config , tag ) ;
2016-08-08 17:33:26 -07:00
}
2016-08-23 13:46:36 -07:00
/**
2016-09-23 16:08:38 -07:00
* Validate a credential and learn it if it passes certificate and other checks
*/
2016-09-26 16:17:02 -07:00
Membership : : AddCredentialResult addCredential ( const Address & sentFrom , const Revocation & rev ) ;
2016-09-23 16:08:38 -07:00
/**
* Force push credentials ( COM , etc . ) to a peer now
2016-08-23 13:46:36 -07:00
*
2016-09-23 16:08:38 -07:00
* @ param to Destination peer address
* @ param now Current time
2016-08-23 13:46:36 -07:00
*/
2016-09-23 16:08:38 -07:00
inline void pushCredentialsNow ( const Address & to , const uint64_t now )
2016-08-23 13:46:36 -07:00
{
Mutex : : Lock _l ( _lock ) ;
2016-09-23 16:08:38 -07:00
_membership ( to ) . pushCredentials ( RR , now , to , _config , - 1 , true ) ;
2016-08-23 13:46:36 -07:00
}
2014-08-21 17:49:05 -07:00
/**
* Destroy this network
*
* This causes the network to disable itself , destroy its tap device , and on
* delete to delete all trace of itself on disk and remove any persistent tap
* device instances . Call this when a network is being removed from the system .
*/
void destroy ( ) ;
2016-01-12 11:04:35 -08:00
/**
2016-09-23 16:08:38 -07:00
* Get this network ' s config for export via the ZT core API
*
* @ param ec Buffer to fill with externally - visible network configuration
*/
inline void externalConfig ( ZT_VirtualNetworkConfig * ec ) const
{
Mutex : : Lock _l ( _lock ) ;
_externalConfig ( ec ) ;
}
/**
* @ return Externally usable pointer - to - pointer exported via the core API
2016-01-12 11:04:35 -08:00
*/
2016-01-12 13:17:30 -08:00
inline void * * userPtr ( ) throw ( ) { return & _uPtr ; }
2016-01-12 11:04:35 -08:00
2013-07-04 16:56:19 -04:00
private :
2016-09-23 16:08:38 -07:00
int _setConfiguration ( const NetworkConfig & nconf , bool saveToDisk ) ;
2015-09-24 16:21:36 -07:00
ZT_VirtualNetworkStatus _status ( ) const ;
void _externalConfig ( ZT_VirtualNetworkConfig * ec ) const ; // assumes _lock is locked
2016-09-08 19:48:05 -07:00
bool _gate ( const SharedPtr < Peer > & peer ) ;
2016-09-09 11:36:10 -07:00
void _sendUpdatesToMembers ( const MulticastGroup * const newMulticastGroup ) ;
2016-09-07 15:15:52 -07:00
void _announceMulticastGroupsTo ( const Address & peer , const std : : vector < MulticastGroup > & allMulticastGroups ) ;
2015-05-25 14:21:05 -07:00
std : : vector < MulticastGroup > _allMulticastGroups ( ) const ;
2016-09-08 19:48:05 -07:00
Membership & _membership ( const Address & a ) ;
2015-04-06 16:52:52 -07:00
2016-09-23 16:08:38 -07:00
const RuntimeEnvironment * const RR ;
2016-01-12 13:17:30 -08:00
void * _uPtr ;
2016-09-23 16:08:38 -07:00
const uint64_t _id ;
2016-09-07 15:15:52 -07:00
uint64_t _lastAnnouncedMulticastGroupsUpstream ;
2014-06-10 17:18:59 -07:00
MAC _mac ; // local MAC address
2016-09-27 11:33:48 -07:00
bool _portInitialized ;
2014-06-10 17:18:59 -07:00
2015-09-04 13:53:48 -07:00
std : : vector < MulticastGroup > _myMulticastGroups ; // multicast groups that we belong to (according to tap)
Hashtable < MulticastGroup , uint64_t > _multicastGroupsBehindMe ; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
2015-09-04 14:14:32 -07:00
Hashtable < MAC , Address > _remoteBridgeRoutes ; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
2014-09-18 18:28:14 -07:00
2016-04-12 12:11:34 -07:00
NetworkConfig _config ;
2016-09-27 11:33:48 -07:00
uint64_t _lastConfigUpdate ;
struct _IncomingConfigChunk
{
uint64_t ts ;
uint64_t updateId ;
uint64_t haveChunkIds [ ZT_NETWORK_MAX_UPDATE_CHUNKS ] ;
unsigned long haveChunks ;
unsigned long haveBytes ;
Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > data ;
} ;
_IncomingConfigChunk _incomingConfigChunks [ ZT_NETWORK_MAX_INCOMING_UPDATES ] ;
2014-06-10 17:18:59 -07:00
2016-09-27 11:33:48 -07:00
bool _destroyed ;
2014-06-10 17:18:59 -07:00
2015-04-06 16:52:52 -07:00
enum {
2014-01-27 23:13:36 -08:00
NETCONF_FAILURE_NONE ,
NETCONF_FAILURE_ACCESS_DENIED ,
NETCONF_FAILURE_NOT_FOUND ,
NETCONF_FAILURE_INIT_FAILED
} _netconfFailure ;
2016-09-27 11:33:48 -07:00
int _portError ; // return value from port config callback
2014-06-10 17:18:59 -07:00
2016-08-05 15:02:01 -07:00
Hashtable < Address , Membership > _memberships ;
2013-07-04 16:56:19 -04:00
Mutex _lock ;
AtomicCounter __refCount ;
} ;
} // naemspace ZeroTier
# endif