2016-08-04 16:51:15 +00:00
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright ( C ) 2011 - 2016 ZeroTier , Inc . https : //www.zerotier.com/
*
* 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/>.
*/
# include "Membership.hpp"
# include "RuntimeEnvironment.hpp"
# include "Peer.hpp"
# include "Topology.hpp"
# include "Switch.hpp"
# include "Packet.hpp"
# include "Node.hpp"
2016-09-09 02:48:05 +00:00
# define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3)
2016-08-04 16:51:15 +00:00
namespace ZeroTier {
2016-08-26 21:43:16 +00:00
void Membership : : sendCredentialsIfNeeded ( const RuntimeEnvironment * RR , const uint64_t now , const Address & peerAddress , const NetworkConfig & nconf , const Capability * cap )
2016-08-04 16:51:15 +00:00
{
2016-09-09 02:48:05 +00:00
if ( ( now - _lastPushAttempt ) < 2000ULL )
2016-08-26 21:43:16 +00:00
return ;
2016-08-26 01:21:20 +00:00
_lastPushAttempt = now ;
2016-08-04 16:51:15 +00:00
try {
2016-08-26 21:43:16 +00:00
bool unfinished ;
do {
unfinished = false ;
Buffer < ZT_PROTO_MAX_PACKET_LENGTH > capsAndTags ;
2016-08-04 16:51:15 +00:00
2016-08-26 21:43:16 +00:00
unsigned int appendedCaps = 0 ;
if ( cap ) {
capsAndTags . addSize ( 2 ) ;
std : : map < uint32_t , CState > : : iterator cs ( _caps . find ( cap - > id ( ) ) ) ;
if ( ( cs ! = _caps . end ( ) ) & & ( ( now - cs - > second . lastPushed ) > = ZT_CREDENTIAL_PUSH_EVERY ) ) {
cap - > serialize ( capsAndTags ) ;
cs - > second . lastPushed = now ;
+ + appendedCaps ;
}
capsAndTags . setAt < uint16_t > ( 0 , ( uint16_t ) appendedCaps ) ;
} else {
capsAndTags . append ( ( uint16_t ) 0 ) ;
2016-08-04 16:51:15 +00:00
}
2016-08-26 21:43:16 +00:00
unsigned int appendedTags = 0 ;
const unsigned int tagCountPos = capsAndTags . size ( ) ;
capsAndTags . addSize ( 2 ) ;
for ( unsigned int i = 0 ; i < nconf . tagCount ; + + i ) {
TState * const ts = _tags . get ( nconf . tags [ i ] . id ( ) ) ;
if ( ( now - ts - > lastPushed ) > = ZT_CREDENTIAL_PUSH_EVERY ) {
if ( ( capsAndTags . size ( ) + sizeof ( Tag ) ) > = ( ZT_PROTO_MAX_PACKET_LENGTH - sizeof ( CertificateOfMembership ) ) ) {
unfinished = true ;
break ;
}
nconf . tags [ i ] . serialize ( capsAndTags ) ;
ts - > lastPushed = now ;
+ + appendedTags ;
}
2016-08-04 16:51:15 +00:00
}
2016-08-26 21:43:16 +00:00
capsAndTags . setAt < uint16_t > ( tagCountPos , ( uint16_t ) appendedTags ) ;
2016-08-04 16:51:15 +00:00
2016-09-09 18:36:10 +00:00
const bool needCom = ( ( nconf . com ) & & ( ( now - _lastPushedCom ) > = ZT_CREDENTIAL_PUSH_EVERY ) ) ;
2016-08-26 21:43:16 +00:00
if ( ( needCom ) | | ( appendedCaps ) | | ( appendedTags ) ) {
Packet outp ( peerAddress , RR - > identity . address ( ) , Packet : : VERB_NETWORK_CREDENTIALS ) ;
if ( needCom ) {
nconf . com . serialize ( outp ) ;
_lastPushedCom = now ;
}
outp . append ( ( uint8_t ) 0x00 ) ;
outp . append ( capsAndTags . data ( ) , capsAndTags . size ( ) ) ;
outp . compress ( ) ;
RR - > sw - > send ( outp , true ) ;
2016-08-26 01:21:20 +00:00
}
2016-08-26 21:43:16 +00:00
} while ( unfinished ) ; // if there are many tags, etc., we can send more than one
2016-08-04 16:51:15 +00:00
} catch ( . . . ) {
TRACE ( " unable to send credentials due to unexpected exception " ) ;
}
}
2016-09-07 22:47:20 +00:00
int Membership : : addCredential ( const RuntimeEnvironment * RR , const CertificateOfMembership & com )
2016-08-04 16:51:15 +00:00
{
2016-08-24 22:45:37 +00:00
if ( _com = = com ) {
TRACE ( " addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant) " , com . issuedTo ( ) . toString ( ) . c_str ( ) , com . networkId ( ) ) ;
2016-08-04 16:51:15 +00:00
return 0 ;
2016-08-24 22:45:37 +00:00
}
2016-09-07 22:15:52 +00:00
2016-08-04 16:51:15 +00:00
const int vr = com . verify ( RR ) ;
2016-09-07 22:15:52 +00:00
2016-08-24 22:45:37 +00:00
if ( vr = = 0 ) {
2016-09-09 02:48:05 +00:00
if ( com . timestamp ( ) . first > = _com . timestamp ( ) . first ) {
TRACE ( " addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new) " , com . issuedTo ( ) . toString ( ) . c_str ( ) , com . networkId ( ) ) ;
2016-08-24 22:45:37 +00:00
_com = com ;
2016-09-09 02:48:05 +00:00
} else {
TRACE ( " addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED but not used (OK but older than current) " , com . issuedTo ( ) . toString ( ) . c_str ( ) , com . networkId ( ) ) ;
2016-08-26 01:21:20 +00:00
}
2016-08-24 22:45:37 +00:00
} else {
TRACE ( " addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (%d) " , com . issuedTo ( ) . toString ( ) . c_str ( ) , com . networkId ( ) , vr ) ;
}
2016-09-07 22:15:52 +00:00
2016-08-04 16:51:15 +00:00
return vr ;
}
2016-08-09 00:33:26 +00:00
int Membership : : addCredential ( const RuntimeEnvironment * RR , const Tag & tag )
2016-08-04 16:51:15 +00:00
{
2016-08-08 23:50:00 +00:00
TState * t = _tags . get ( tag . id ( ) ) ;
2016-08-24 22:45:37 +00:00
if ( ( t ) & & ( t - > lastReceived ! = 0 ) & & ( t - > tag = = tag ) ) {
TRACE ( " addCredential(Tag) for %s on %.16llx ACCEPTED (redundant) " , tag . issuedTo ( ) . toString ( ) . c_str ( ) , tag . networkId ( ) ) ;
2016-08-04 16:51:15 +00:00
return 0 ;
2016-08-24 22:45:37 +00:00
}
2016-08-04 16:51:15 +00:00
const int vr = tag . verify ( RR ) ;
if ( vr = = 0 ) {
2016-08-24 22:45:37 +00:00
TRACE ( " addCredential(Tag) for %s on %.16llx ACCEPTED (new) " , tag . issuedTo ( ) . toString ( ) . c_str ( ) , tag . networkId ( ) ) ;
2016-08-25 00:24:35 +00:00
if ( ! t ) {
while ( _tags . size ( ) > = ZT_MAX_NETWORK_TAGS ) {
uint32_t oldest = 0 ;
uint64_t oldestLastReceived = 0xffffffffffffffffULL ;
uint32_t * i = ( uint32_t * ) 0 ;
TState * ts = ( TState * ) 0 ;
Hashtable < uint32_t , TState > : : Iterator tsi ( _tags ) ;
while ( tsi . next ( i , ts ) ) {
if ( ts - > lastReceived < oldestLastReceived ) {
oldestLastReceived = ts - > lastReceived ;
oldest = * i ;
}
}
if ( oldestLastReceived ! = 0xffffffffffffffffULL )
_tags . erase ( oldest ) ;
}
2016-08-08 23:50:00 +00:00
t = & ( _tags [ tag . id ( ) ] ) ;
2016-08-25 00:24:35 +00:00
}
2016-08-09 00:33:26 +00:00
if ( t - > tag . timestamp ( ) < = tag . timestamp ( ) ) {
t - > lastReceived = RR - > node - > now ( ) ;
t - > tag = tag ;
}
2016-08-24 22:45:37 +00:00
} else {
TRACE ( " addCredential(Tag) for %s on %.16llx REJECTED (%d) " , tag . issuedTo ( ) . toString ( ) . c_str ( ) , tag . networkId ( ) , vr ) ;
2016-08-04 16:51:15 +00:00
}
return vr ;
}
2016-08-09 00:33:26 +00:00
int Membership : : addCredential ( const RuntimeEnvironment * RR , const Capability & cap )
2016-08-04 16:51:15 +00:00
{
2016-08-08 23:50:00 +00:00
std : : map < uint32_t , CState > : : iterator c ( _caps . find ( cap . id ( ) ) ) ;
2016-08-24 22:45:37 +00:00
if ( ( c ! = _caps . end ( ) ) & & ( c - > second . lastReceived ! = 0 ) & & ( c - > second . cap = = cap ) ) {
TRACE ( " addCredential(Capability) for %s on %.16llx ACCEPTED (redundant) " , cap . issuedTo ( ) . toString ( ) . c_str ( ) , cap . networkId ( ) ) ;
2016-08-04 16:51:15 +00:00
return 0 ;
2016-08-24 22:45:37 +00:00
}
2016-08-04 16:51:15 +00:00
const int vr = cap . verify ( RR ) ;
if ( vr = = 0 ) {
2016-08-24 22:45:37 +00:00
TRACE ( " addCredential(Capability) for %s on %.16llx ACCEPTED (new) " , cap . issuedTo ( ) . toString ( ) . c_str ( ) , cap . networkId ( ) ) ;
2016-08-08 23:50:00 +00:00
if ( c = = _caps . end ( ) ) {
2016-08-25 00:24:35 +00:00
while ( _caps . size ( ) > = ZT_MAX_NETWORK_CAPABILITIES ) {
std : : map < uint32_t , CState > : : iterator oldest ;
uint64_t oldestLastReceived = 0xffffffffffffffffULL ;
for ( std : : map < uint32_t , CState > : : iterator i ( _caps . begin ( ) ) ; i ! = _caps . end ( ) ; + + i ) {
if ( i - > second . lastReceived < oldestLastReceived ) {
oldestLastReceived = i - > second . lastReceived ;
oldest = i ;
}
}
if ( oldestLastReceived ! = 0xffffffffffffffffULL )
_caps . erase ( oldest ) ;
}
2016-08-08 23:50:00 +00:00
CState & c2 = _caps [ cap . id ( ) ] ;
2016-08-09 00:33:26 +00:00
c2 . lastReceived = RR - > node - > now ( ) ;
2016-08-08 23:50:00 +00:00
c2 . cap = cap ;
2016-08-09 00:33:26 +00:00
} else if ( c - > second . cap . timestamp ( ) < = cap . timestamp ( ) ) {
c - > second . lastReceived = RR - > node - > now ( ) ;
2016-08-08 23:50:00 +00:00
c - > second . cap = cap ;
}
2016-08-24 22:45:37 +00:00
} else {
TRACE ( " addCredential(Capability) for %s on %.16llx REJECTED (%d) " , cap . issuedTo ( ) . toString ( ) . c_str ( ) , cap . networkId ( ) , vr ) ;
2016-08-04 16:51:15 +00:00
}
return vr ;
}
} // namespace ZeroTier