2015-04-07 17:57:59 +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/
*/
2015-04-07 18:56:10 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2015-04-07 17:57:59 +00:00
# include "Constants.hpp"
# include "SelfAwareness.hpp"
# include "RuntimeEnvironment.hpp"
# include "Node.hpp"
# include "Topology.hpp"
# include "Packet.hpp"
# include "Peer.hpp"
2015-05-05 01:34:30 +00:00
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
# define ZT_SELFAWARENESS_ENTRY_TIMEOUT 3600000
2015-04-07 17:57:59 +00:00
namespace ZeroTier {
2015-04-07 18:56:10 +00:00
class _ResetWithinScope
{
public :
_ResetWithinScope ( const RuntimeEnvironment * renv , uint64_t now , InetAddress : : IpScope scope ) :
RR ( renv ) ,
_now ( now ) ,
_scope ( scope ) { }
2015-05-01 04:09:41 +00:00
inline void operator ( ) ( Topology & t , const SharedPtr < Peer > & p )
{
if ( p - > resetWithinScope ( RR , _scope , _now ) )
peersReset . push_back ( p ) ;
}
std : : vector < SharedPtr < Peer > > peersReset ;
2015-04-07 18:56:10 +00:00
private :
const RuntimeEnvironment * RR ;
uint64_t _now ;
InetAddress : : IpScope _scope ;
} ;
2015-04-07 17:57:59 +00:00
SelfAwareness : : SelfAwareness ( const RuntimeEnvironment * renv ) :
RR ( renv )
{
}
SelfAwareness : : ~ SelfAwareness ( )
{
}
2015-05-05 01:34:30 +00:00
void SelfAwareness : : iam ( const Address & reporter , const InetAddress & reporterPhysicalAddress , const InetAddress & myPhysicalAddress , bool trusted , uint64_t now )
2015-04-07 17:57:59 +00:00
{
2015-05-05 01:34:30 +00:00
const InetAddress : : IpScope scope = myPhysicalAddress . ipScope ( ) ;
switch ( scope ) {
case InetAddress : : IP_SCOPE_NONE :
case InetAddress : : IP_SCOPE_LOOPBACK :
case InetAddress : : IP_SCOPE_MULTICAST :
2015-04-07 18:56:10 +00:00
return ;
2015-05-05 01:34:30 +00:00
case InetAddress : : IP_SCOPE_GLOBAL :
if ( ( ! trusted ) | | ( scope ! = reporterPhysicalAddress . ipScope ( ) ) )
return ;
break ;
default :
if ( scope ! = reporterPhysicalAddress . ipScope ( ) )
return ;
break ;
}
Mutex : : Lock _l ( _phy_m ) ;
2015-10-23 20:03:34 +00:00
PhySurfaceEntry & entry = _phy [ PhySurfaceKey ( reporter , reporterPhysicalAddress , scope ) ] ;
2015-05-05 01:34:30 +00:00
2015-05-05 01:43:24 +00:00
if ( ( now - entry . ts ) > = ZT_SELFAWARENESS_ENTRY_TIMEOUT ) {
2015-05-05 01:34:30 +00:00
entry . mySurface = myPhysicalAddress ;
entry . ts = now ;
TRACE ( " learned physical address %s for scope %u as seen from %s(%s) (replaced <null>) " , myPhysicalAddress . toString ( ) . c_str ( ) , ( unsigned int ) scope , reporter . toString ( ) . c_str ( ) , reporterPhysicalAddress . toString ( ) . c_str ( ) ) ;
} else if ( entry . mySurface ! = myPhysicalAddress ) {
entry . mySurface = myPhysicalAddress ;
entry . ts = now ;
TRACE ( " learned physical address %s for scope %u as seen from %s(%s) (replaced %s, resetting all in scope) " , myPhysicalAddress . toString ( ) . c_str ( ) , ( unsigned int ) scope , reporter . toString ( ) . c_str ( ) , reporterPhysicalAddress . toString ( ) . c_str ( ) , entry . mySurface . toString ( ) . c_str ( ) ) ;
2015-10-23 20:03:34 +00:00
// Erase all entries in this scope that were not reported by this remote address to prevent 'thrashing'
// due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified.
2015-09-04 21:24:31 +00:00
{
Hashtable < PhySurfaceKey , PhySurfaceEntry > : : Iterator i ( _phy ) ;
PhySurfaceKey * k = ( PhySurfaceKey * ) 0 ;
PhySurfaceEntry * e = ( PhySurfaceEntry * ) 0 ;
while ( i . next ( k , e ) ) {
2015-10-23 20:03:34 +00:00
if ( ( k - > reporterPhysicalAddress ! = reporterPhysicalAddress ) & & ( k - > scope = = scope ) )
2015-09-04 21:24:31 +00:00
_phy . erase ( * k ) ;
}
2015-05-05 02:02:36 +00:00
}
2015-05-05 01:34:30 +00:00
_ResetWithinScope rset ( RR , now , ( InetAddress : : IpScope ) scope ) ;
RR - > topology - > eachPeer < _ResetWithinScope & > ( rset ) ;
// For all peers for whom we forgot an address, send a packet indirectly if
// they are still considered alive so that we will re-establish direct links.
2015-10-27 19:01:00 +00:00
SharedPtr < Peer > r ( RR - > topology - > getBestRoot ( ) ) ;
if ( r ) {
2015-10-27 22:00:16 +00:00
Path * rp = r - > getBestPath ( now ) ;
2015-10-27 19:01:00 +00:00
if ( rp ) {
2015-05-05 01:34:30 +00:00
for ( std : : vector < SharedPtr < Peer > > : : const_iterator p ( rset . peersReset . begin ( ) ) ; p ! = rset . peersReset . end ( ) ; + + p ) {
if ( ( * p ) - > alive ( now ) ) {
2015-10-27 19:01:00 +00:00
TRACE ( " sending indirect NOP to %s via %s to re-establish link " , ( * p ) - > address ( ) . toString ( ) . c_str ( ) , r - > address ( ) . toString ( ) . c_str ( ) ) ;
2015-05-05 01:34:30 +00:00
Packet outp ( ( * p ) - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_NOP ) ;
outp . armor ( ( * p ) - > key ( ) , true ) ;
2015-10-27 19:01:00 +00:00
rp - > send ( RR , outp . data ( ) , outp . size ( ) , now ) ;
2015-05-01 04:09:41 +00:00
}
}
2015-04-07 18:58:41 +00:00
}
2015-04-07 18:56:10 +00:00
}
2015-05-05 02:02:36 +00:00
} else {
entry . ts = now ;
}
2015-04-07 17:57:59 +00:00
}
2015-05-05 01:34:30 +00:00
void SelfAwareness : : clean ( uint64_t now )
{
Mutex : : Lock _l ( _phy_m ) ;
2015-09-04 21:24:31 +00:00
Hashtable < PhySurfaceKey , PhySurfaceEntry > : : Iterator i ( _phy ) ;
PhySurfaceKey * k = ( PhySurfaceKey * ) 0 ;
PhySurfaceEntry * e = ( PhySurfaceEntry * ) 0 ;
while ( i . next ( k , e ) ) {
if ( ( now - e - > ts ) > = ZT_SELFAWARENESS_ENTRY_TIMEOUT )
_phy . erase ( * k ) ;
2015-07-28 18:28:47 +00:00
}
}
2015-04-07 17:57:59 +00:00
} // namespace ZeroTier