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"
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 )
{
2015-04-07 18:56:10 +00:00
memset ( _lastPhysicalAddress , 0 , sizeof ( _lastPhysicalAddress ) ) ;
2015-04-07 17:57:59 +00:00
}
SelfAwareness : : ~ SelfAwareness ( )
{
}
2015-04-17 19:19:01 +00:00
void SelfAwareness : : iam ( const Address & reporter , const InetAddress & reporterPhysicalAddress , const InetAddress & myPhysicalAddress , bool trusted )
2015-04-07 17:57:59 +00:00
{
2015-04-07 18:56:10 +00:00
// This code depends on the numeric values assigned to scopes in InetAddress.hpp
2015-04-07 18:58:41 +00:00
const unsigned int scope = ( unsigned int ) myPhysicalAddress . ipScope ( ) ;
2015-04-07 18:56:10 +00:00
if ( ( scope > 0 ) & & ( scope < ( unsigned int ) InetAddress : : IP_SCOPE_LOOPBACK ) ) {
2015-04-17 19:19:01 +00:00
if ( ( ! trusted ) & & ( ( scope = = ( unsigned int ) InetAddress : : IP_SCOPE_GLOBAL ) | | ( scope ! = ( unsigned int ) reporterPhysicalAddress . ipScope ( ) ) ) ) {
/* For now only trusted peers are permitted to inform us of changes to
* our global Internet IP or to changes of NATed IPs . We ' ll let peers on
* private , shared , or link - local networks inform us of changes as long
* as they too are at the same scope . This discrimination avoids a DoS
* attack in which an attacker could force us to reset our connections . */
2015-04-07 18:56:10 +00:00
return ;
2015-04-17 19:19:01 +00:00
} else {
2015-04-07 18:58:41 +00:00
Mutex : : Lock _l ( _lock ) ;
InetAddress & lastPhy = _lastPhysicalAddress [ scope - 1 ] ;
2015-04-07 19:32:05 +00:00
if ( ! lastPhy ) {
2015-04-17 19:19:01 +00:00
TRACE ( " learned physical address %s for scope %u from reporter %s(%s) (replaced <null>) " , myPhysicalAddress . toString ( ) . c_str ( ) , scope , reporter . toString ( ) . c_str ( ) , reporterPhysicalAddress . toString ( ) . c_str ( ) ) ;
2015-04-07 19:32:05 +00:00
lastPhy = myPhysicalAddress ;
} else if ( lastPhy ! = myPhysicalAddress ) {
2015-04-17 19:19:01 +00:00
TRACE ( " learned physical address %s for scope %u from reporter %s(%s) (replaced %s, resetting within scope) " , myPhysicalAddress . toString ( ) . c_str ( ) , scope , reporter . toString ( ) . c_str ( ) , reporterPhysicalAddress . toString ( ) . c_str ( ) , lastPhy . toString ( ) . c_str ( ) ) ;
2015-04-07 18:58:41 +00:00
lastPhy = myPhysicalAddress ;
2015-05-01 04:09:41 +00:00
uint64_t now = RR - > node - > now ( ) ;
_ResetWithinScope rset ( RR , now , ( InetAddress : : IpScope ) scope ) ;
2015-04-07 18:58:41 +00:00
RR - > topology - > eachPeer < _ResetWithinScope & > ( rset ) ;
2015-05-01 04:09:41 +00:00
// 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.
SharedPtr < Peer > sn ( RR - > topology - > getBestSupernode ( ) ) ;
if ( sn ) {
Path * snp = sn - > getBestPath ( now ) ;
if ( snp ) {
for ( std : : vector < SharedPtr < Peer > > : : const_iterator p ( rset . peersReset . begin ( ) ) ; p ! = rset . peersReset . end ( ) ; + + p ) {
if ( ( * p ) - > alive ( now ) ) {
TRACE ( " sending indirect NOP to %s via %s(%s) to re-establish link " , ( * p ) - > address ( ) . toString ( ) . c_str ( ) , sn - > address ( ) . toString ( ) . c_str ( ) , snp - > address ( ) . toString ( ) . c_str ( ) ) ;
Packet outp ( ( * p ) - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_NOP ) ;
outp . armor ( ( * p ) - > key ( ) , true ) ;
snp - > send ( RR , outp . data ( ) , outp . size ( ) , now ) ;
}
}
}
}
2015-04-07 18:58:41 +00:00
}
2015-04-07 18:56:10 +00:00
}
}
2015-04-07 17:57:59 +00:00
}
} // namespace ZeroTier