2013-07-04 20:56:19 +00:00
/*
* ZeroTier One - Global Peer to Peer Ethernet
2015-01-06 01:47:59 +00:00
* Copyright ( C ) 2011 - 2015 ZeroTier Networks
2013-07-04 20:56:19 +00: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/>.
*
* - -
*
* 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/
*/
2013-08-06 04:05:39 +00:00
# include <stdio.h>
# include <string.h>
2013-07-29 17:56:20 +00:00
# include <stdlib.h>
# include <math.h>
2014-04-07 22:39:33 +00:00
# include "Constants.hpp"
2013-10-18 16:01:48 +00:00
# include "Network.hpp"
2013-07-29 17:56:20 +00:00
# include "RuntimeEnvironment.hpp"
# include "NodeConfig.hpp"
2013-07-04 20:56:19 +00:00
# include "Switch.hpp"
2013-07-30 15:14:53 +00:00
# include "Packet.hpp"
2013-10-16 21:47:26 +00:00
# include "Buffer.hpp"
2014-07-31 21:09:32 +00:00
# include "EthernetTap.hpp"
# include "EthernetTapFactory.hpp"
2014-08-13 00:20:34 +00:00
# include "RoutingTable.hpp"
2013-10-16 21:47:26 +00:00
2013-10-21 15:15:47 +00:00
# define ZT_NETWORK_CERT_WRITE_BUF_SIZE 131072
2013-07-04 20:56:19 +00:00
namespace ZeroTier {
2014-05-23 22:13:34 +00:00
const ZeroTier : : MulticastGroup Network : : BROADCAST ( ZeroTier : : MAC ( 0xff ) , 0 ) ;
2013-08-08 14:41:17 +00:00
const char * Network : : statusString ( const Status s )
throw ( )
{
switch ( s ) {
2014-01-28 07:13:36 +00:00
case NETWORK_INITIALIZING : return " INITIALIZING " ;
2013-08-08 14:41:17 +00:00
case NETWORK_WAITING_FOR_FIRST_AUTOCONF : return " WAITING_FOR_FIRST_AUTOCONF " ;
case NETWORK_OK : return " OK " ;
case NETWORK_ACCESS_DENIED : return " ACCESS_DENIED " ;
2013-10-16 21:47:26 +00:00
case NETWORK_NOT_FOUND : return " NOT_FOUND " ;
2014-01-28 07:16:15 +00:00
case NETWORK_INITIALIZATION_FAILED : return " INITIALIZATION_FAILED " ;
2014-06-27 00:05:07 +00:00
case NETWORK_NO_MORE_DEVICES : return " NO_MORE_DEVICES " ;
2013-08-08 14:41:17 +00:00
}
return " (invalid) " ;
}
2013-08-06 05:28:56 +00:00
Network : : ~ Network ( )
{
2014-08-22 01:07:27 +00:00
_lock . lock ( ) ;
if ( ( _setupThread ) & & ( ! _destroyed ) ) {
_lock . unlock ( ) ;
Thread : : join ( _setupThread ) ;
} else _lock . unlock ( ) ;
2014-01-28 07:13:36 +00:00
2014-08-22 00:49:05 +00:00
{
Mutex : : Lock _l ( _lock ) ;
if ( _tap )
2014-09-24 20:53:03 +00:00
RR - > tapFactory - > close ( _tap , _destroyed ) ;
2014-08-22 00:49:05 +00:00
}
2014-01-27 06:47:08 +00:00
2014-08-22 00:49:05 +00:00
if ( _destroyed ) {
2014-09-24 20:53:03 +00:00
Utils : : rm ( std : : string ( RR - > homePath + ZT_PATH_SEPARATOR_S + " networks.d " + ZT_PATH_SEPARATOR_S + idString ( ) + " .conf " ) ) ;
Utils : : rm ( std : : string ( RR - > homePath + ZT_PATH_SEPARATOR_S + " networks.d " + ZT_PATH_SEPARATOR_S + idString ( ) + " .mcerts " ) ) ;
2013-08-06 05:28:56 +00:00
} else {
clean ( ) ;
2014-09-26 19:23:43 +00:00
_dumpMembershipCerts ( ) ;
2013-08-06 05:28:56 +00:00
}
}
2014-02-11 22:21:59 +00:00
SharedPtr < Network > Network : : newInstance ( const RuntimeEnvironment * renv , NodeConfig * nc , uint64_t id )
2013-08-06 05:28:56 +00:00
{
2013-08-06 14:15:05 +00:00
SharedPtr < Network > nw ( new Network ( ) ) ;
2013-10-18 16:01:48 +00:00
nw - > _id = id ;
2014-02-11 22:21:59 +00:00
nw - > _nc = nc ;
2014-05-23 21:32:31 +00:00
nw - > _mac . fromAddress ( renv - > identity . address ( ) , id ) ;
2014-09-26 05:13:31 +00:00
nw - > RR = renv ;
2014-01-28 07:13:36 +00:00
nw - > _tap = ( EthernetTap * ) 0 ;
2014-06-27 00:05:07 +00:00
nw - > _enabled = true ;
2013-08-06 14:15:05 +00:00
nw - > _lastConfigUpdate = 0 ;
2014-08-22 00:49:05 +00:00
nw - > _destroyed = false ;
2014-01-28 07:13:36 +00:00
nw - > _netconfFailure = NETCONF_FAILURE_NONE ;
2014-07-31 21:09:32 +00:00
if ( nw - > controller ( ) = = renv - > identity . address ( ) ) // TODO: fix Switch to allow packets to self
2013-10-16 21:47:26 +00:00
throw std : : runtime_error ( " cannot join a network for which I am the netconf master " ) ;
2014-01-28 07:13:36 +00:00
2014-07-31 21:09:32 +00:00
try {
nw - > _restoreState ( ) ;
nw - > requestConfiguration ( ) ;
} catch ( . . . ) {
nw - > _lastConfigUpdate = 0 ; // call requestConfiguration() again
}
2013-10-18 16:01:48 +00:00
2013-08-06 14:15:05 +00:00
return nw ;
2013-07-04 20:56:19 +00:00
}
2014-10-04 01:27:42 +00:00
// Function object used by rescanMulticastGroups()
class AnnounceMulticastGroupsToPeersWithActiveDirectPaths
2014-06-13 21:06:34 +00:00
{
2014-10-04 01:27:42 +00:00
public :
AnnounceMulticastGroupsToPeersWithActiveDirectPaths ( const RuntimeEnvironment * renv , Network * nw ) :
RR ( renv ) ,
_now ( Utils : : now ( ) ) ,
2014-10-14 23:38:27 +00:00
_network ( nw ) ,
_supernodeAddresses ( renv - > topology - > supernodeAddresses ( ) )
2014-10-04 01:27:42 +00:00
{ }
inline void operator ( ) ( Topology & t , const SharedPtr < Peer > & p )
{
2014-10-14 23:38:27 +00:00
if ( ( ( p - > hasActiveDirectPath ( _now ) ) & & ( _network - > isAllowed ( p - > address ( ) ) ) ) | | ( std : : find ( _supernodeAddresses . begin ( ) , _supernodeAddresses . end ( ) , p - > address ( ) ) ! = _supernodeAddresses . end ( ) ) ) {
2014-10-04 01:27:42 +00:00
Packet outp ( p - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_MULTICAST_LIKE ) ;
std : : set < MulticastGroup > mgs ( _network - > multicastGroups ( ) ) ;
for ( std : : set < MulticastGroup > : : iterator mg ( mgs . begin ( ) ) ; mg ! = mgs . end ( ) ; + + mg ) {
if ( ( outp . size ( ) + 18 ) > ZT_UDP_DEFAULT_PAYLOAD_MTU ) {
outp . armor ( p - > key ( ) , true ) ;
p - > send ( RR , outp . data ( ) , outp . size ( ) , _now ) ;
outp . reset ( p - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_MULTICAST_LIKE ) ;
}
// network ID, MAC, ADI
outp . append ( ( uint64_t ) _network - > id ( ) ) ;
mg - > mac ( ) . appendTo ( outp ) ;
outp . append ( ( uint32_t ) mg - > adi ( ) ) ;
}
if ( outp . size ( ) > ZT_PROTO_MIN_PACKET_LENGTH ) {
outp . armor ( p - > key ( ) , true ) ;
p - > send ( RR , outp . data ( ) , outp . size ( ) , _now ) ;
2014-06-13 21:06:34 +00:00
}
}
2014-10-04 01:27:42 +00:00
}
private :
const RuntimeEnvironment * RR ;
uint64_t _now ;
Network * _network ;
2014-10-14 23:38:27 +00:00
std : : vector < Address > _supernodeAddresses ;
2014-10-04 01:27:42 +00:00
} ;
bool Network : : rescanMulticastGroups ( )
{
bool updated = false ;
{
Mutex : : Lock _l ( _lock ) ;
EthernetTap * t = _tap ;
if ( t ) {
// Grab current groups from the local tap
updated = t - > updateMulticastGroups ( _myMulticastGroups ) ;
// Merge in learned groups from any hosts bridged in behind us
for ( std : : map < MulticastGroup , uint64_t > : : const_iterator mg ( _multicastGroupsBehindMe . begin ( ) ) ; mg ! = _multicastGroupsBehindMe . end ( ) ; + + mg )
_myMulticastGroups . insert ( mg - > first ) ;
// Add or remove BROADCAST group based on broadcast enabled netconf flag
if ( ( _config ) & & ( _config - > enableBroadcast ( ) ) ) {
if ( ! _myMulticastGroups . count ( BROADCAST ) ) {
_myMulticastGroups . insert ( BROADCAST ) ;
updated = true ;
}
} else {
if ( _myMulticastGroups . count ( BROADCAST ) ) {
_myMulticastGroups . erase ( BROADCAST ) ;
updated = true ;
}
}
}
}
if ( updated ) {
AnnounceMulticastGroupsToPeersWithActiveDirectPaths afunc ( RR , this ) ;
RR - > topology - > eachPeer < AnnounceMulticastGroupsToPeersWithActiveDirectPaths & > ( afunc ) ;
}
return updated ;
2014-06-13 21:06:34 +00:00
}
2014-10-03 23:14:34 +00:00
bool Network : : applyConfiguration ( const SharedPtr < NetworkConfig > & conf )
2013-07-29 17:56:20 +00:00
{
2014-01-28 07:13:36 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-08-22 00:49:05 +00:00
if ( _destroyed )
return false ;
2013-09-04 13:27:56 +00:00
try {
2014-10-03 23:14:34 +00:00
if ( ( conf - > networkId ( ) = = _id ) & & ( conf - > issuedTo ( ) = = RR - > identity . address ( ) ) ) {
2014-10-04 20:15:02 +00:00
std : : vector < InetAddress > oldStaticIps ;
2014-09-05 22:35:09 +00:00
if ( _config )
oldStaticIps = _config - > staticIps ( ) ;
2014-10-03 23:14:34 +00:00
_config = conf ;
2013-09-24 21:35:05 +00:00
2013-10-18 16:01:48 +00:00
_lastConfigUpdate = Utils : : now ( ) ;
2014-01-28 07:13:36 +00:00
_netconfFailure = NETCONF_FAILURE_NONE ;
2013-10-16 21:47:26 +00:00
2014-07-31 21:09:32 +00:00
EthernetTap * t = _tap ;
if ( t ) {
char fname [ 1024 ] ;
_mkNetworkFriendlyName ( fname , sizeof ( fname ) ) ;
t - > setFriendlyName ( fname ) ;
2014-09-05 22:35:09 +00:00
// Remove previously configured static IPs that are gone
2014-10-04 20:15:02 +00:00
for ( std : : vector < InetAddress > : : const_iterator oldip ( oldStaticIps . begin ( ) ) ; oldip ! = oldStaticIps . end ( ) ; + + oldip ) {
if ( std : : find ( _config - > staticIps ( ) . begin ( ) , _config - > staticIps ( ) . end ( ) , * oldip ) = = _config - > staticIps ( ) . end ( ) )
2014-09-05 22:35:09 +00:00
t - > removeIP ( * oldip ) ;
}
// Add new static IPs that were not in previous config
2014-10-04 20:15:02 +00:00
for ( std : : vector < InetAddress > : : const_iterator newip ( _config - > staticIps ( ) . begin ( ) ) ; newip ! = _config - > staticIps ( ) . end ( ) ; + + newip ) {
if ( std : : find ( oldStaticIps . begin ( ) , oldStaticIps . end ( ) , * newip ) = = oldStaticIps . end ( ) )
2014-09-05 22:35:09 +00:00
t - > addIP ( * newip ) ;
}
# ifdef __APPLE__
// Make sure there's an IPv6 link-local address on Macs if IPv6 is enabled
// Other OSes don't need this -- Mac seems not to want to auto-assign
// This might go away once we integrate properly w/Mac network setup stuff.
if ( _config - > permitsEtherType ( ZT_ETHERTYPE_IPV6 ) ) {
bool haveV6LinkLocal = false ;
std : : set < InetAddress > ips ( t - > ips ( ) ) ;
for ( std : : set < InetAddress > : : const_iterator i ( ips . begin ( ) ) ; i ! = ips . end ( ) ; + + i ) {
if ( ( i - > isV6 ( ) ) & & ( i - > isLinkLocal ( ) ) ) {
haveV6LinkLocal = true ;
break ;
}
}
if ( ! haveV6LinkLocal )
t - > addIP ( InetAddress : : makeIpv6LinkLocal ( _mac ) ) ;
}
# endif // __APPLE__
// ... IPs that were never controlled by static assignment are left
// alone, as these may be DHCP or user-configured.
2014-07-31 21:09:32 +00:00
} else {
if ( ! _setupThread )
_setupThread = Thread : : start < Network > ( this ) ;
}
2014-01-28 07:13:36 +00:00
return true ;
2013-10-18 16:01:48 +00:00
} else {
LOG ( " ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address) " , ( unsigned long long ) _id ) ;
2013-08-06 04:05:39 +00:00
}
2013-10-18 16:01:48 +00:00
} catch ( std : : exception & exc ) {
LOG ( " ignored invalid configuration for network %.16llx (%s) " , ( unsigned long long ) _id , exc . what ( ) ) ;
2013-09-04 13:27:56 +00:00
} catch ( . . . ) {
2013-10-18 16:01:48 +00:00
LOG ( " ignored invalid configuration for network %.16llx (unknown exception) " , ( unsigned long long ) _id ) ;
2013-07-30 15:14:53 +00:00
}
2014-01-28 07:13:36 +00:00
return false ;
2013-07-29 17:56:20 +00:00
}
2015-01-06 01:47:59 +00:00
int Network : : setConfiguration ( const Dictionary & conf , bool saveToDisk )
2014-10-03 23:14:34 +00:00
{
try {
SharedPtr < NetworkConfig > newConfig ( new NetworkConfig ( conf ) ) ; // throws if invalid
2015-01-06 01:47:59 +00:00
{
Mutex : : Lock _l ( _lock ) ;
if ( ( _config ) & & ( * _config = = * newConfig ) )
return 1 ; // OK but duplicate
}
2014-10-03 23:14:34 +00:00
if ( applyConfiguration ( newConfig ) ) {
if ( saveToDisk ) {
std : : string confPath ( RR - > homePath + ZT_PATH_SEPARATOR_S + " networks.d " + ZT_PATH_SEPARATOR_S + idString ( ) + " .conf " ) ;
if ( ! Utils : : writeFile ( confPath . c_str ( ) , conf . toString ( ) ) ) {
LOG ( " error: unable to write network configuration file at: %s " , confPath . c_str ( ) ) ;
} else {
Utils : : lockDownFile ( confPath . c_str ( ) , false ) ;
}
}
2015-01-06 01:47:59 +00:00
return 2 ; // OK and configuration has changed
2014-10-03 23:14:34 +00:00
}
} catch ( . . . ) {
LOG ( " ignored invalid configuration for network %.16llx (dictionary decode failed) " , ( unsigned long long ) _id ) ;
}
2015-01-06 01:47:59 +00:00
return 0 ;
2014-10-03 23:14:34 +00:00
}
2013-07-29 17:56:20 +00:00
void Network : : requestConfiguration ( )
{
2014-10-03 23:14:34 +00:00
if ( _id = = ZT_TEST_NETWORK_ID ) // pseudo-network-ID, no netconf master
return ;
2014-09-24 20:53:03 +00:00
if ( controller ( ) = = RR - > identity . address ( ) ) {
2013-10-16 21:47:26 +00:00
// netconf master cannot be a member of its own nets
2013-08-05 20:06:16 +00:00
LOG ( " unable to request network configuration for network %.16llx: I am the network master, cannot query self " , ( unsigned long long ) _id ) ;
return ;
}
2013-09-24 21:35:05 +00:00
2013-08-05 20:06:16 +00:00
TRACE ( " requesting netconf for network %.16llx from netconf master %s " , ( unsigned long long ) _id , controller ( ) . toString ( ) . c_str ( ) ) ;
2014-09-24 20:53:03 +00:00
Packet outp ( controller ( ) , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CONFIG_REQUEST ) ;
2013-07-30 15:14:53 +00:00
outp . append ( ( uint64_t ) _id ) ;
2013-08-06 04:05:39 +00:00
outp . append ( ( uint16_t ) 0 ) ; // no meta-data
2015-01-06 01:51:50 +00:00
{
Mutex : : Lock _l ( _lock ) ;
if ( _config )
outp . append ( ( uint64_t ) _config - > timestamp ( ) ) ;
else outp . append ( ( uint64_t ) 0 ) ;
}
2014-09-24 20:53:03 +00:00
RR - > sw - > send ( outp , true ) ;
2013-07-29 17:56:20 +00:00
}
2014-10-01 00:26:34 +00:00
void Network : : addMembershipCertificate ( const CertificateOfMembership & cert , bool forceAccept )
2013-08-06 04:05:39 +00:00
{
2013-10-25 17:43:04 +00:00
if ( ! cert ) // sanity check
return ;
2014-11-13 20:40:51 +00:00
Mutex : : Lock _l ( _lock ) ;
CertificateOfMembership & old = _membershipCertificates [ cert . issuedTo ( ) ] ;
// Nothing to do if the cert hasn't changed -- we get duplicates due to zealous cert pushing
if ( old = = cert )
return ;
// Check signature, log and return if cert is invalid
2014-10-01 00:26:34 +00:00
if ( ! forceAccept ) {
2014-10-14 19:37:35 +00:00
if ( cert . signedBy ( ) ! = controller ( ) ) {
LOG ( " rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network " , ( unsigned long long ) _id , cert . signedBy ( ) . toString ( ) . c_str ( ) ) ;
2014-10-01 00:26:34 +00:00
return ;
2014-10-14 19:37:35 +00:00
}
2014-10-01 00:26:34 +00:00
SharedPtr < Peer > signer ( RR - > topology - > getPeer ( cert . signedBy ( ) ) ) ;
2014-10-14 19:37:35 +00:00
if ( ! signer ) {
// This would be rather odd, since this is our netconf master... could happen
// if we get packets before we've gotten config.
RR - > sw - > requestWhois ( cert . signedBy ( ) ) ;
2014-10-01 00:26:34 +00:00
return ;
2014-10-14 19:37:35 +00:00
}
if ( ! cert . verify ( signer - > identity ( ) ) ) {
LOG ( " rejected network membership certificate for %.16llx signed by %s: signature check failed " , ( unsigned long long ) _id , cert . signedBy ( ) . toString ( ) . c_str ( ) ) ;
return ;
}
2014-10-01 00:26:34 +00:00
}
2014-11-13 20:40:51 +00:00
// If we made it past authentication, update cert
2014-10-14 19:37:35 +00:00
if ( cert . timestamp ( ) > = old . timestamp ( ) )
2013-10-17 10:41:52 +00:00
old = cert ;
2013-08-06 04:05:39 +00:00
}
2014-10-09 19:42:25 +00:00
bool Network : : peerNeedsOurMembershipCertificate ( const Address & to , uint64_t now )
{
Mutex : : Lock _l ( _lock ) ;
if ( ( _config ) & & ( ! _config - > isPublic ( ) ) & & ( _config - > com ( ) ) ) {
uint64_t pushInterval = _config - > com ( ) . timestampMaxDelta ( ) / 2 ;
if ( pushInterval ) {
// Give a 1s margin around +/- 1/2 max delta to account for network latency
if ( pushInterval > 1000 )
pushInterval - = 1000 ;
uint64_t & lastPushed = _lastPushedMembershipCertificate [ to ] ;
if ( ( now - lastPushed ) > pushInterval ) {
lastPushed = now ;
return true ;
}
}
}
return false ;
}
2013-07-29 21:11:00 +00:00
bool Network : : isAllowed ( const Address & peer ) const
{
try {
Mutex : : Lock _l ( _lock ) ;
2013-10-18 16:01:48 +00:00
if ( ! _config )
return false ;
2014-06-14 20:24:19 +00:00
if ( _config - > isPublic ( ) )
2013-10-18 16:01:48 +00:00
return true ;
2013-09-11 19:13:05 +00:00
std : : map < Address , CertificateOfMembership > : : const_iterator pc ( _membershipCertificates . find ( peer ) ) ;
2013-07-29 21:11:00 +00:00
if ( pc = = _membershipCertificates . end ( ) )
2013-10-16 21:47:26 +00:00
return false ; // no certificate on file
2014-10-09 19:42:25 +00:00
2013-10-18 16:01:48 +00:00
return _config - > com ( ) . agreesWith ( pc - > second ) ; // is other cert valid against ours?
2013-07-29 21:11:00 +00:00
} catch ( std : : exception & exc ) {
TRACE ( " isAllowed() check failed for peer %s: unexpected exception: %s " , peer . toString ( ) . c_str ( ) , exc . what ( ) ) ;
} catch ( . . . ) {
TRACE ( " isAllowed() check failed for peer %s: unexpected exception: unknown exception " , peer . toString ( ) . c_str ( ) ) ;
}
2013-10-16 21:47:26 +00:00
return false ; // default position on any failure
2013-07-29 21:11:00 +00:00
}
void Network : : clean ( )
{
2014-09-24 16:01:58 +00:00
uint64_t now = Utils : : now ( ) ;
2014-09-30 23:28:25 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-08-22 00:49:05 +00:00
2014-09-30 23:28:25 +00:00
if ( _destroyed )
return ;
2014-08-22 00:49:05 +00:00
2014-09-30 23:28:25 +00:00
if ( ( _config ) & & ( _config - > isPublic ( ) ) ) {
// Open (public) networks do not track certs or cert pushes at all.
_membershipCertificates . clear ( ) ;
_lastPushedMembershipCertificate . clear ( ) ;
} else if ( _config ) {
// Clean certificates that are no longer valid from the cache.
for ( std : : map < Address , CertificateOfMembership > : : iterator c = ( _membershipCertificates . begin ( ) ) ; c ! = _membershipCertificates . end ( ) ; ) {
if ( _config - > com ( ) . agreesWith ( c - > second ) )
+ + c ;
else _membershipCertificates . erase ( c + + ) ;
2013-08-06 04:05:39 +00:00
}
2014-09-30 23:28:25 +00:00
// Clean entries from the last pushed tracking map if they're so old as
// to be no longer relevant.
uint64_t forgetIfBefore = now - ( _config - > com ( ) . timestampMaxDelta ( ) * 3ULL ) ;
for ( std : : map < Address , uint64_t > : : iterator lp ( _lastPushedMembershipCertificate . begin ( ) ) ; lp ! = _lastPushedMembershipCertificate . end ( ) ; ) {
if ( lp - > second < forgetIfBefore )
_lastPushedMembershipCertificate . erase ( lp + + ) ;
else + + lp ;
2013-08-03 16:53:46 +00:00
}
2013-07-29 21:11:00 +00:00
}
2014-09-30 23:28:25 +00:00
// Clean learned multicast groups if we haven't heard from them in a while
for ( std : : map < MulticastGroup , uint64_t > : : iterator mg ( _multicastGroupsBehindMe . begin ( ) ) ; mg ! = _multicastGroupsBehindMe . end ( ) ; ) {
if ( ( now - mg - > second ) > ( ZT_MULTICAST_LIKE_EXPIRE * 2 ) )
_multicastGroupsBehindMe . erase ( mg + + ) ;
else + + mg ;
2014-06-13 21:06:34 +00:00
}
}
Network : : Status Network : : status ( ) const
{
Mutex : : Lock _l ( _lock ) ;
2014-08-22 00:49:05 +00:00
switch ( _netconfFailure ) {
case NETCONF_FAILURE_ACCESS_DENIED :
return NETWORK_ACCESS_DENIED ;
case NETCONF_FAILURE_NOT_FOUND :
return NETWORK_NOT_FOUND ;
case NETCONF_FAILURE_NONE :
return ( ( _lastConfigUpdate > 0 ) ? ( ( _tap ) ? NETWORK_OK : NETWORK_INITIALIZING ) : NETWORK_WAITING_FOR_FIRST_AUTOCONF ) ;
//case NETCONF_FAILURE_INIT_FAILED:
default :
return NETWORK_INITIALIZATION_FAILED ;
}
2013-07-29 21:11:00 +00:00
}
2014-09-26 19:23:43 +00:00
void Network : : learnBridgeRoute ( const MAC & mac , const Address & addr )
2013-07-04 20:56:19 +00:00
{
2014-09-26 19:23:43 +00:00
Mutex : : Lock _l ( _lock ) ;
_remoteBridgeRoutes [ mac ] = addr ;
2013-10-16 21:47:26 +00:00
2014-09-26 19:23:43 +00:00
// If _remoteBridgeRoutes exceeds sanity limit, trim worst offenders until below -- denial of service circuit breaker
while ( _remoteBridgeRoutes . size ( ) > ZT_MAX_BRIDGE_ROUTES ) {
std : : map < Address , unsigned long > counts ;
Address maxAddr ;
unsigned long maxCount = 0 ;
for ( std : : map < MAC , Address > : : iterator br ( _remoteBridgeRoutes . begin ( ) ) ; br ! = _remoteBridgeRoutes . end ( ) ; + + br ) {
unsigned long c = + + counts [ br - > second ] ;
if ( c > maxCount ) {
maxCount = c ;
maxAddr = br - > second ;
}
}
for ( std : : map < MAC , Address > : : iterator br ( _remoteBridgeRoutes . begin ( ) ) ; br ! = _remoteBridgeRoutes . end ( ) ; ) {
if ( br - > second = = maxAddr )
_remoteBridgeRoutes . erase ( br + + ) ;
else + + br ;
}
2013-07-04 20:56:19 +00:00
}
}
2014-09-26 19:23:43 +00:00
void Network : : setEnabled ( bool enabled )
2013-10-07 21:00:53 +00:00
{
2014-09-26 19:23:43 +00:00
Mutex : : Lock _l ( _lock ) ;
_enabled = enabled ;
if ( _tap )
_tap - > setEnabled ( enabled ) ;
}
2013-10-07 21:00:53 +00:00
2014-09-26 19:23:43 +00:00
void Network : : destroy ( )
{
Mutex : : Lock _l ( _lock ) ;
2013-10-07 21:00:53 +00:00
2014-09-26 19:23:43 +00:00
_enabled = false ;
_destroyed = true ;
if ( _setupThread )
Thread : : join ( _setupThread ) ;
_setupThread = Thread ( ) ;
if ( _tap )
RR - > tapFactory - > close ( _tap , true ) ;
_tap = ( EthernetTap * ) 0 ;
2013-10-07 21:00:53 +00:00
}
2014-07-31 21:09:32 +00:00
// Ethernet tap creation thread -- required on some platforms where tap
2014-09-26 19:23:43 +00:00
// creation may be time consuming (e.g. Windows). Thread exits after tap
// device setup.
2014-01-28 07:13:36 +00:00
void Network : : threadMain ( )
2014-01-28 07:16:15 +00:00
throw ( )
2014-01-28 07:13:36 +00:00
{
2014-07-31 21:09:32 +00:00
char fname [ 1024 ] , lcentry [ 128 ] ;
Utils : : snprintf ( lcentry , sizeof ( lcentry ) , " _dev_for_%.16llx " , ( unsigned long long ) _id ) ;
2014-02-11 22:21:59 +00:00
2014-08-08 02:08:41 +00:00
EthernetTap * t = ( EthernetTap * ) 0 ;
2014-01-28 07:13:36 +00:00
try {
2014-07-31 21:09:32 +00:00
std : : string desiredDevice ( _nc - > getLocalConfig ( lcentry ) ) ;
_mkNetworkFriendlyName ( fname , sizeof ( fname ) ) ;
2014-09-24 20:53:03 +00:00
t = RR - > tapFactory - > open ( _mac , ZT_IF_MTU , ZT_DEFAULT_IF_METRIC , _id , ( desiredDevice . length ( ) > 0 ) ? desiredDevice . c_str ( ) : ( const char * ) 0 , fname , _CBhandleTapData , this ) ;
2014-07-31 21:09:32 +00:00
std : : string dn ( t - > deviceName ( ) ) ;
if ( ( dn . length ( ) ) & & ( dn ! = desiredDevice ) )
2014-02-11 22:21:59 +00:00
_nc - > putLocalConfig ( lcentry , dn ) ;
2014-01-28 07:13:36 +00:00
} catch ( std : : exception & exc ) {
2014-07-31 21:09:32 +00:00
delete t ;
t = ( EthernetTap * ) 0 ;
2014-01-28 07:13:36 +00:00
LOG ( " network %.16llx failed to initialize: %s " , _id , exc . what ( ) ) ;
_netconfFailure = NETCONF_FAILURE_INIT_FAILED ;
} catch ( . . . ) {
2014-07-31 21:09:32 +00:00
delete t ;
t = ( EthernetTap * ) 0 ;
2014-01-28 07:13:36 +00:00
LOG ( " network %.16llx failed to initialize: unknown error " , _id ) ;
_netconfFailure = NETCONF_FAILURE_INIT_FAILED ;
}
2014-07-31 21:09:32 +00:00
{
Mutex : : Lock _l ( _lock ) ;
if ( _tap ) // the tap creation thread can technically be re-launched, though this isn't done right now
2014-09-24 20:53:03 +00:00
RR - > tapFactory - > close ( _tap , false ) ;
2014-07-31 21:09:32 +00:00
_tap = t ;
if ( t ) {
2014-09-05 22:35:09 +00:00
if ( _config ) {
2014-10-04 20:15:02 +00:00
for ( std : : vector < InetAddress > : : const_iterator newip ( _config - > staticIps ( ) . begin ( ) ) ; newip ! = _config - > staticIps ( ) . end ( ) ; + + newip )
2014-09-05 22:35:09 +00:00
t - > addIP ( * newip ) ;
}
2014-07-31 21:09:32 +00:00
t - > setEnabled ( _enabled ) ;
}
2014-01-28 07:13:36 +00:00
}
2014-10-14 23:38:27 +00:00
rescanMulticastGroups ( ) ;
2014-01-28 07:13:36 +00:00
}
2014-09-26 19:23:43 +00:00
void Network : : _CBhandleTapData ( void * arg , const MAC & from , const MAC & to , unsigned int etherType , const Buffer < 4096 > & data )
2014-06-11 00:18:59 +00:00
{
2014-10-29 20:57:37 +00:00
SharedPtr < Network > network ( ( Network * ) arg , true ) ;
if ( ( ! network ) | | ( ! network - > _enabled ) | | ( network - > status ( ) ! = NETWORK_OK ) )
2014-09-26 19:23:43 +00:00
return ;
try {
2014-10-29 20:57:37 +00:00
network - > RR - > sw - > onLocalEthernet ( network , from , to , etherType , data ) ;
2014-09-26 19:23:43 +00:00
} catch ( std : : exception & exc ) {
TRACE ( " unexpected exception handling local packet: %s " , exc . what ( ) ) ;
} catch ( . . . ) {
TRACE ( " unexpected exception handling local packet " ) ;
2014-06-11 00:18:59 +00:00
}
}
2013-08-06 14:15:05 +00:00
void Network : : _restoreState ( )
{
2013-10-16 21:47:26 +00:00
Buffer < ZT_NETWORK_CERT_WRITE_BUF_SIZE > buf ;
std : : string idstr ( idString ( ) ) ;
2014-09-24 20:53:03 +00:00
std : : string confPath ( RR - > homePath + ZT_PATH_SEPARATOR_S + " networks.d " + ZT_PATH_SEPARATOR_S + idstr + " .conf " ) ;
std : : string mcdbPath ( RR - > homePath + ZT_PATH_SEPARATOR_S + " networks.d " + ZT_PATH_SEPARATOR_S + idstr + " .mcerts " ) ;
2013-10-16 21:47:26 +00:00
2014-10-03 23:14:34 +00:00
if ( _id = = ZT_TEST_NETWORK_ID ) {
applyConfiguration ( NetworkConfig : : createTestNetworkConfig ( RR - > identity . address ( ) ) ) ;
// "Touch" path to this ID to remember test network membership
FILE * tmp = fopen ( confPath . c_str ( ) , " w " ) ;
if ( tmp ) fclose ( tmp ) ;
} else {
// Read configuration file containing last config from netconf master
{
std : : string confs ;
if ( Utils : : readFile ( confPath . c_str ( ) , confs ) ) {
try {
if ( confs . length ( ) )
setConfiguration ( Dictionary ( confs ) , false ) ;
} catch ( . . . ) { } // ignore invalid config on disk, we will re-request from netconf master
} else {
// "Touch" path to remember membership in lieu of real config from netconf master
FILE * tmp = fopen ( confPath . c_str ( ) , " w " ) ;
if ( tmp ) fclose ( tmp ) ;
}
2013-10-16 21:47:26 +00:00
}
}
2014-10-03 23:14:34 +00:00
{ // Read most recent membership cert dump if there is one
2013-10-16 21:47:26 +00:00
Mutex : : Lock _l ( _lock ) ;
2014-10-03 23:14:34 +00:00
if ( ( _config ) & & ( ! _config - > isPublic ( ) ) & & ( Utils : : fileExists ( mcdbPath . c_str ( ) ) ) ) {
CertificateOfMembership com ;
_membershipCertificates . clear ( ) ;
FILE * mcdb = fopen ( mcdbPath . c_str ( ) , " rb " ) ;
if ( mcdb ) {
try {
char magic [ 6 ] ;
if ( ( fread ( magic , 6 , 1 , mcdb ) = = 1 ) & & ( ! memcmp ( " ZTMCD0 " , magic , 6 ) ) ) {
long rlen = 0 ;
do {
long rlen = ( long ) fread ( const_cast < char * > ( static_cast < const char * > ( buf . data ( ) ) ) + buf . size ( ) , 1 , ZT_NETWORK_CERT_WRITE_BUF_SIZE - buf . size ( ) , mcdb ) ;
if ( rlen < 0 ) rlen = 0 ;
buf . setSize ( buf . size ( ) + ( unsigned int ) rlen ) ;
unsigned int ptr = 0 ;
while ( ( ptr < ( ZT_NETWORK_CERT_WRITE_BUF_SIZE / 2 ) ) & & ( ptr < buf . size ( ) ) ) {
ptr + = com . deserialize ( buf , ptr ) ;
if ( com . issuedTo ( ) )
_membershipCertificates [ com . issuedTo ( ) ] = com ;
}
buf . behead ( ptr ) ;
} while ( rlen > 0 ) ;
fclose ( mcdb ) ;
} else {
fclose ( mcdb ) ;
Utils : : rm ( mcdbPath ) ;
}
} catch ( . . . ) {
// Membership cert dump file invalid. We'll re-learn them off the net.
_membershipCertificates . clear ( ) ;
2013-10-17 10:41:52 +00:00
fclose ( mcdb ) ;
Utils : : rm ( mcdbPath ) ;
2013-10-16 21:47:26 +00:00
}
}
}
2013-08-06 14:15:05 +00:00
}
2013-10-16 21:47:26 +00:00
}
2014-09-26 19:23:43 +00:00
void Network : : _dumpMembershipCerts ( )
2013-10-16 21:47:26 +00:00
{
Buffer < ZT_NETWORK_CERT_WRITE_BUF_SIZE > buf ;
2014-09-24 20:53:03 +00:00
std : : string mcdbPath ( RR - > homePath + ZT_PATH_SEPARATOR_S + " networks.d " + ZT_PATH_SEPARATOR_S + idString ( ) + " .mcerts " ) ;
2013-10-16 21:47:26 +00:00
Mutex : : Lock _l ( _lock ) ;
2013-10-18 16:01:48 +00:00
if ( ! _config )
return ;
2014-06-14 20:24:19 +00:00
if ( ( ! _id ) | | ( _config - > isPublic ( ) ) ) {
2013-10-16 21:47:26 +00:00
Utils : : rm ( mcdbPath ) ;
return ;
}
FILE * mcdb = fopen ( mcdbPath . c_str ( ) , " wb " ) ;
if ( ! mcdb )
return ;
2014-10-14 19:37:35 +00:00
2013-10-16 21:47:26 +00:00
if ( fwrite ( " ZTMCD0 " , 6 , 1 , mcdb ) ! = 1 ) {
2013-10-21 15:15:47 +00:00
fclose ( mcdb ) ;
2013-10-16 21:47:26 +00:00
Utils : : rm ( mcdbPath ) ;
return ;
}
for ( std : : map < Address , CertificateOfMembership > : : iterator c = ( _membershipCertificates . begin ( ) ) ; c ! = _membershipCertificates . end ( ) ; + + c ) {
2014-10-14 19:37:35 +00:00
buf . clear ( ) ;
c - > second . serialize ( buf ) ;
if ( buf . size ( ) > 0 ) {
if ( fwrite ( buf . data ( ) , buf . size ( ) , 1 , mcdb ) ! = 1 ) {
fclose ( mcdb ) ;
Utils : : rm ( mcdbPath ) ;
return ;
2013-10-16 21:47:26 +00:00
}
}
}
fclose ( mcdb ) ;
2014-01-26 18:32:12 +00:00
Utils : : lockDownFile ( mcdbPath . c_str ( ) , false ) ;
2013-08-06 14:15:05 +00:00
}
2013-07-04 20:56:19 +00:00
} // namespace ZeroTier