@ -62,11 +62,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
return true ;
}
} else if ( ( c = = ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE ) & & ( verb ( ) = = Packet : : VERB_HELLO ) ) {
// A null pointer for peer to _doHELLO() tells it to run its own
// special internal authentication logic. This is done for unencrypted
// HELLOs to learn new identities, etc.
SharedPtr < Peer > tmp ;
return _doHELLO ( RR , tmp ) ;
// Only HELLO is allowed in the clear, but will still have a MAC
return _doHELLO ( RR , false ) ;
}
SharedPtr < Peer > peer ( RR - > topology - > getPeer ( sourceAddress ) ) ;
@ -91,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
peer - > received ( _path , hops ( ) , packetId ( ) , v , 0 , Packet : : VERB_NOP , false ) ;
return true ;
case Packet : : VERB_HELLO : return _doHELLO ( RR , peer ) ;
case Packet : : VERB_HELLO : return _doHELLO ( RR , true ) ;
case Packet : : VERB_ERROR : return _doERROR ( RR , peer ) ;
case Packet : : VERB_OK : return _doOK ( RR , peer ) ;
case Packet : : VERB_WHOIS : return _doWHOIS ( RR , peer ) ;
@ -192,16 +189,16 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
return true ;
}
bool IncomingPacket : : _doHELLO ( const RuntimeEnvironment * RR , SharedPtr < Peer > & peer )
bool IncomingPacket : : _doHELLO ( const RuntimeEnvironment * RR , const bool alreadyAuthenticated )
{
/* Note: this is the only packet ever sent in the clear, and it's also
* the only packet that we authenticate via a different path . Authentication
* occurs here and is based on the validity of the identity and the
* integrity of the packet ' s MAC , but it must be done after we check
* the identity since HELLO is a mechanism for learning new identities
* in the first place . */
try {
const uint64_t now = RR - > node - > now ( ) ;
if ( ! _path - > rateGateHello ( now ) ) {
TRACE ( " dropped HELLO from %s(%s): rate limiting circuit breaker for HELLO on this path tripped " , source ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
const uint64_t pid = packetId ( ) ;
const Address fromAddress ( source ( ) ) ;
const unsigned int protoVersion = ( * this ) [ ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION ] ;
@ -228,20 +225,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
}
}
if ( protoVersion < ZT_PROTO_VERSION_MIN ) {
TRACE ( " dropped HELLO from %s(%s): protocol version too old " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
if ( fromAddress ! = id . address ( ) ) {
TRACE ( " dropped HELLO from %s(%s): identity not for sending address " , fromAddress . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
if ( protoVersion < ZT_PROTO_VERSION_MIN ) {
TRACE ( " dropped HELLO from %s(%s): protocol version too old " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
if ( ! peer ) { // peer == NULL is the normal case here
peer = RR - > topology - > getPeer ( id . address ( ) ) ;
if ( peer ) {
// We already have an identity with this address -- check for collisions
SharedPtr < Peer > peer ( RR - > topology - > getPeer ( id . address ( ) ) ) ;
if ( peer ) {
// We already have an identity with this address -- check for collisions
if ( ! alreadyAuthenticated ) {
if ( peer - > identity ( ) ! = id ) {
// Identity is different from the one we already have -- address collision
@ -273,31 +269,37 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
// Continue at // VALID
}
} else {
// We don't already have an identity with this address -- validate and learn it
} // else continue at // VALID
} else {
// We don't already have an identity with this address -- validate and learn it
// Check identity proof of work
if ( ! id . locallyValidate ( ) ) {
TRACE ( " dropped HELLO from %s(%s): identity invalid " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
// Sanity check: this basically can't happen
if ( alreadyAuthenticated ) {
TRACE ( " dropped HELLO from %s(%s): somehow already authenticated with unknown peer? " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
// Check packet integrity and authentication
SharedPtr < Peer > newPeer ( new Peer ( RR , RR - > identity , id ) ) ;
if ( ! dearmor ( newPeer - > key ( ) ) ) {
TRACE ( " rejected HELLO from %s(%s): packet failed authentication " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
peer = RR - > topology - > addPeer ( newPeer ) ;
// Check identity proof of work
if ( ! id . locallyValidate ( ) ) {
TRACE ( " dropped HELLO from %s(%s): identity invalid " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
// Continue at // VALID
// Check packet integrity and authentication
SharedPtr < Peer > newPeer ( new Peer ( RR , RR - > identity , id ) ) ;
if ( ! dearmor ( newPeer - > key ( ) ) ) {
TRACE ( " rejected HELLO from %s(%s): packet failed authentication " , id . address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
peer = RR - > topology - > addPeer ( newPeer ) ;
// VALID -- if we made it here, packet passed identity and authenticity checks!
// Continue at // VALID
}
// VALID -- if we made it here, packet passed identity and authenticity checks!
if ( ( externalSurfaceAddress ) & & ( hops ( ) = = 0 ) )
RR - > sa - > iam ( id . address ( ) , _path - > localAddress ( ) , _path - > address ( ) , externalSurfaceAddress , RR - > topology - > isUpstream ( id ) , RR - > node - > now ( ) ) ;
RR - > sa - > iam ( id . address ( ) , _path - > localAddress ( ) , _path - > address ( ) , externalSurfaceAddress , RR - > topology - > isUpstream ( id ) , now ) ;
Packet outp ( id . address ( ) , RR - > identity . address ( ) , Packet : : VERB_OK ) ;
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
@ -349,7 +351,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
}
outp . armor ( peer - > key ( ) , true ) ;
_path - > send ( RR , outp . data ( ) , outp . size ( ) , RR - > node - > now ( ) ) ;
_path - > send ( RR , outp . data ( ) , outp . size ( ) , now ) ;
peer - > setRemoteVersion ( protoVersion , vMajor , vMinor , vRevision ) ; // important for this to go first so received() knows the version
peer - > received ( _path , hops ( ) , pid , Packet : : VERB_HELLO , 0 , Packet : : VERB_NOP , false ) ;
@ -443,7 +445,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
case Packet : : VERB_MULTICAST_GATHER : {
const uint64_t nwid = at < uint64_t > ( ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID ) ;
SharedPtr < Network > network ( RR - > node - > network ( nwid ) ) ;
if ( ( network ) & & ( network - > gateMulticastGather ( peer , verb ( ) , packetId ( ) ) ) ) {
if ( ( network ) & & ( network - > gateMulticastGatherReply ( peer , verb ( ) , packetId ( ) ) ) ) {
const MulticastGroup mg ( MAC ( field ( ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC , 6 ) , 6 ) , at < uint32_t > ( ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI ) ) ;
//TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size());
const unsigned int count = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4 ) ;
@ -469,7 +471,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
network - > addCredential ( com ) ;
}
if ( network - > gateMulticastGather ( peer , verb ( ) , packetId ( ) ) ) {
if ( network - > gateMulticastGatherReply ( peer , verb ( ) , packetId ( ) ) ) {
if ( ( flags & 0x02 ) ! = 0 ) {
// OK(MULTICAST_FRAME) includes implicit gather results
offset + = ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS ;
@ -494,6 +496,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
bool IncomingPacket : : _doWHOIS ( const RuntimeEnvironment * RR , const SharedPtr < Peer > & peer )
{
try {
if ( ! peer - > rateGateInboundWhoisRequest ( RR - > node - > now ( ) ) ) {
TRACE ( " dropped WHOIS from %s(%s): rate limit circuit breaker tripped " , source ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
Packet outp ( peer - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_OK ) ;
outp . append ( ( unsigned char ) Packet : : VERB_WHOIS ) ;
outp . append ( packetId ( ) ) ;
@ -672,6 +679,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
bool IncomingPacket : : _doECHO ( const RuntimeEnvironment * RR , const SharedPtr < Peer > & peer )
{
try {
if ( ! peer - > rateGateEchoRequest ( RR - > node - > now ( ) ) ) {
TRACE ( " dropped ECHO from %s(%s): rate limit circuit breaker tripped " , source ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
const uint64_t pid = packetId ( ) ;
Packet outp ( peer - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_OK ) ;
outp . append ( ( unsigned char ) Packet : : VERB_ECHO ) ;
@ -680,6 +692,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer>
outp . append ( reinterpret_cast < const unsigned char * > ( data ( ) ) + ZT_PACKET_IDX_PAYLOAD , size ( ) - ZT_PACKET_IDX_PAYLOAD ) ;
outp . armor ( peer - > key ( ) , true ) ;
_path - > send ( RR , outp . data ( ) , outp . size ( ) , RR - > node - > now ( ) ) ;
peer - > received ( _path , hops ( ) , pid , Packet : : VERB_ECHO , 0 , Packet : : VERB_NOP , false ) ;
} catch ( . . . ) {
TRACE ( " dropped ECHO from %s(%s): unexpected exception " , source ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
@ -692,11 +705,35 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
try {
const uint64_t now = RR - > node - > now ( ) ;
uint64_t authOnNetwork [ 256 ] ;
unsigned int authOnNetworkCount = 0 ;
SharedPtr < Network > network ;
// Iterate through 18-byte network,MAC,ADI tuples
for ( unsigned int ptr = ZT_PACKET_IDX_PAYLOAD ; ptr < size ( ) ; ptr + = 18 ) {
const uint64_t nwid = at < uint64_t > ( ptr ) ;
const MulticastGroup group ( MAC ( field ( ptr + 8 , 6 ) , 6 ) , at < uint32_t > ( ptr + 14 ) ) ;
RR - > mc - > add ( now , nwid , group , peer - > address ( ) ) ;
bool auth = false ;
for ( unsigned int i = 0 ; i < authOnNetworkCount ; + + i ) {
if ( nwid = = authOnNetwork [ i ] ) {
auth = true ;
break ;
}
}
if ( ! auth ) {
if ( ( ! network ) | | ( network - > id ( ) ! = nwid ) )
network = RR - > node - > network ( nwid ) ;
if ( ( ( network ) & & ( network - > gate ( peer , verb ( ) , packetId ( ) ) ) ) | | RR - > mc - > cacheAuthorized ( peer - > address ( ) , nwid , now ) ) {
auth = true ;
if ( authOnNetworkCount < 256 ) // sanity check, packets can't really be this big
authOnNetwork [ authOnNetworkCount + + ] = nwid ;
}
}
if ( auth ) {
const MulticastGroup group ( MAC ( field ( ptr + 8 , 6 ) , 6 ) , at < uint32_t > ( ptr + 14 ) ) ;
RR - > mc - > add ( now , nwid , group , peer - > address ( ) ) ;
}
}
peer - > received ( _path , hops ( ) , packetId ( ) , Packet : : VERB_MULTICAST_LIKE , 0 , Packet : : VERB_NOP , false ) ;
@ -721,7 +758,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
if ( network ) {
if ( network - > addCredential ( com ) = = 1 )
return false ; // wait for WHOIS
}
} else RR - > mc - > addCredential ( com , false ) ;
}
}
+ + p ; // skip trailing 0 after COMs if present
@ -759,22 +796,21 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
{
try {
const uint64_t nwid = at < uint64_t > ( ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID ) ;
const unsigned int metaDataLength = at < uint16_t > ( ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN ) ;
const char * metaDataBytes = ( const char * ) field ( ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT , metaDataLength ) ;
const Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > metaData ( metaDataBytes , metaDataLength ) ;
const unsigned int hopCount = hops ( ) ;
const uint64_t requestPacketId = packetId ( ) ;
bool netconfOk = false ;
bool trustEstablished = false ;
if ( RR - > localNetworkController ) {
const unsigned int metaDataLength = at < uint16_t > ( ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN ) ;
const char * metaDataBytes = ( const char * ) field ( ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT , metaDataLength ) ;
const Dictionary < ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY > metaData ( metaDataBytes , metaDataLength ) ;
NetworkConfig * netconf = new NetworkConfig ( ) ;
try {
switch ( RR - > localNetworkController - > doNetworkConfigRequest ( ( hopCount > 0 ) ? InetAddress ( ) : _path - > address ( ) , RR - > identity , peer - > identity ( ) , nwid , metaData , * netconf ) ) {
case NetworkController : : NETCONF_QUERY_OK : {
netconfOk = true ;
trustEstablished = true ;
Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > * dconf = new Dictionary < ZT_NETWORKCONFIG_DICT_CAPACITY > ( ) ;
try {
if ( netconf - > toDictionary ( * dconf , metaData . getUI ( ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION , 0 ) < 6 ) ) {
@ -846,7 +882,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
_path - > send ( RR , outp . data ( ) , outp . size ( ) , RR - > node - > now ( ) ) ;
}
peer - > received ( _path , hopCount , requestPacketId , Packet : : VERB_NETWORK_CONFIG_REQUEST , 0 , Packet : : VERB_NOP , netconfOk ) ;
peer - > received ( _path , hopCount , requestPacketId , Packet : : VERB_NETWORK_CONFIG_REQUEST , 0 , Packet : : VERB_NOP , trustEstablished ) ;
} catch ( std : : exception & exc ) {
fprintf ( stderr , " WARNING: network config request failed with exception: %s " ZT_EOL_S , exc . what ( ) ) ;
TRACE ( " dropped NETWORK_CONFIG_REQUEST from %s(%s): %s " , source ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) , exc . what ( ) ) ;
@ -897,21 +933,23 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
//TRACE("<<MC %s(%s) GATHER up to %u in %.16llx/%s",source().toString().c_str(),_path->address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str());
const SharedPtr < Network > network ( RR - > node - > network ( nwid ) ) ;
if ( ( flags & 0x01 ) ! = 0 ) {
try {
CertificateOfMembership com ;
com . deserialize ( * this , ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM ) ;
if ( com ) {
SharedPtr < Network > network ( RR - > node - > network ( nwid ) ) ;
if ( network )
network - > addCredential ( com ) ;
else RR - > mc - > addCredential ( com , false ) ;
}
} catch ( . . . ) {
TRACE ( " MULTICAST_GATHER from %s(%s): discarded invalid COM " , peer - > address ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
}
}
if ( gatherLimit ) {
if ( ( ( ( network ) & & ( network - > gate ( peer , verb ( ) , packetId ( ) ) ) ) | | ( RR - > mc - > cacheAuthorized ( peer - > address ( ) , nwid , RR - > node - > now ( ) ) ) ) & & ( gatherLimit > 0 ) ) {
Packet outp ( peer - > address ( ) , RR - > identity . address ( ) , Packet : : VERB_OK ) ;
outp . append ( ( unsigned char ) Packet : : VERB_MULTICAST_GATHER ) ;
outp . append ( packetId ( ) ) ;
@ -1043,7 +1081,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
const uint64_t now = RR - > node - > now ( ) ;
// First, subject this to a rate limit
if ( ! peer - > shouldRespondToDirectPathPush ( now ) ) {
if ( ! peer - > rateGatePushDirectPaths ( now ) ) {
TRACE ( " dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped " , source ( ) . toString ( ) . c_str ( ) , _path - > address ( ) . toString ( ) . c_str ( ) ) ;
peer - > received ( _path , hops ( ) , packetId ( ) , Packet : : VERB_PUSH_DIRECT_PATHS , 0 , Packet : : VERB_NOP , false ) ;
return true ;