2013-07-11 20:19:06 +00:00
/*
* ZeroTier One - Global Peer to Peer Ethernet
* Copyright ( C ) 2012 - 2013 ZeroTier Networks LLC
*
* 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/
*/
# include "RuntimeEnvironment.hpp"
# include "Topology.hpp"
# include "PacketDecoder.hpp"
# include "Switch.hpp"
2013-07-11 21:52:04 +00:00
# include "Peer.hpp"
2013-07-12 02:06:25 +00:00
# include "NodeConfig.hpp"
# include "Filter.hpp"
2013-07-11 20:19:06 +00:00
namespace ZeroTier {
bool PacketDecoder : : tryDecode ( const RuntimeEnvironment * _r )
throw ( std : : out_of_range , std : : runtime_error )
{
2013-07-11 21:52:04 +00:00
if ( ( ! encrypted ( ) ) & & ( verb ( ) = = Packet : : VERB_HELLO ) ) {
// Unencrypted HELLOs are handled here since they are used to
// populate our identity cache in the first place. Thus we might get
// a HELLO for someone for whom we don't have a Peer record.
2013-07-12 02:06:25 +00:00
TRACE ( " HELLO from %s(%s) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
return _doHELLO ( _r ) ;
}
2013-07-12 02:06:25 +00:00
SharedPtr < Peer > peer = _r - > topology - > getPeer ( source ( ) ) ;
2013-07-11 21:52:04 +00:00
if ( peer ) {
2013-07-12 02:06:25 +00:00
if ( _step = = DECODE_STEP_WAITING_FOR_ORIGINAL_SUBMITTER_LOOKUP ) {
// This means we've already decoded, decrypted, decompressed, and
// validated, and we're processing a MULTICAST_FRAME. We're waiting
2013-07-12 14:13:24 +00:00
// for a lookup on the frame's original submitter. So try again and
// see if we have it.
2013-07-12 02:06:25 +00:00
return _doMULTICAST_FRAME ( _r , peer ) ;
}
2013-07-11 22:15:51 +00:00
if ( ! hmacVerify ( peer - > macKey ( ) ) ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped packet from %s(%s), HMAC authentication failed (size: %u) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , size ( ) ) ;
2013-07-11 21:52:04 +00:00
return true ;
}
2013-07-11 22:15:51 +00:00
if ( encrypted ( ) ) {
decrypt ( peer - > cryptKey ( ) ) ;
2013-07-11 21:52:04 +00:00
} else {
// Unencrypted is tolerated in case we want to run this on
// devices where squeezing out cycles matters. HMAC is
2013-07-12 14:13:24 +00:00
// what's really important. But log it in debug to catch any
// packets being mistakenly sent in the clear.
2013-07-12 02:06:25 +00:00
TRACE ( " ODD: %s from %s(%s) wasn't encrypted " , Packet : : verbString ( verb ( ) ) , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 21:52:04 +00:00
}
2013-07-11 22:15:51 +00:00
if ( ! uncompress ( ) ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped packet from %s(%s), compressed data invalid " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 21:52:04 +00:00
return true ;
}
2013-07-12 02:06:25 +00:00
Packet : : Verb v = verb ( ) ;
2013-07-11 22:15:51 +00:00
// Validated packets that have passed HMAC can result in us learning a new
// path to this peer.
2013-07-12 02:06:25 +00:00
peer - > onReceive ( _r , _localPort , _remoteAddress , hops ( ) , v , Utils : : now ( ) ) ;
2013-07-11 22:15:51 +00:00
2013-07-12 02:06:25 +00:00
switch ( v ) {
2013-07-11 21:52:04 +00:00
case Packet : : VERB_NOP :
2013-07-12 02:06:25 +00:00
TRACE ( " NOP from %s(%s) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
return true ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_HELLO :
2013-07-11 22:15:51 +00:00
return _doHELLO ( _r ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_ERROR :
2013-07-12 02:06:25 +00:00
return _doERROR ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_OK :
2013-07-12 02:06:25 +00:00
return _doOK ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_WHOIS :
2013-07-12 02:06:25 +00:00
return _doWHOIS ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_RENDEZVOUS :
2013-07-12 02:06:25 +00:00
return _doRENDEZVOUS ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_FRAME :
2013-07-12 02:06:25 +00:00
return _doFRAME ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_MULTICAST_LIKE :
2013-07-12 02:06:25 +00:00
return _doMULTICAST_LIKE ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
case Packet : : VERB_MULTICAST_FRAME :
2013-07-12 02:06:25 +00:00
return _doMULTICAST_FRAME ( _r , peer ) ;
2013-07-11 21:52:04 +00:00
default :
// This might be something from a new or old version of the protocol.
// Technically it passed HMAC so the packet is still valid, but we
// ignore it.
2013-07-12 02:06:25 +00:00
TRACE ( " ignored unrecognized verb %.2x from %s(%s) " , ( unsigned int ) v , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
return true ;
2013-07-11 21:52:04 +00:00
}
} else {
2013-07-12 14:13:24 +00:00
_step = DECODE_STEP_WAITING_FOR_SENDER_LOOKUP ;
2013-07-12 02:06:25 +00:00
_r - > sw - > requestWhois ( source ( ) ) ;
2013-07-11 21:52:04 +00:00
return false ;
}
2013-07-11 22:15:51 +00:00
}
2013-07-11 21:52:04 +00:00
2013-07-12 02:06:25 +00:00
void PacketDecoder : : _CBaddPeerFromHello ( void * arg , const SharedPtr < Peer > & p , Topology : : PeerVerifyResult result )
{
_CBaddPeerFromHello_Data * req = ( _CBaddPeerFromHello_Data * ) arg ;
const RuntimeEnvironment * _r = req - > renv ;
switch ( result ) {
case Topology : : PEER_VERIFY_ACCEPTED_NEW :
case Topology : : PEER_VERIFY_ACCEPTED_ALREADY_HAVE :
case Topology : : PEER_VERIFY_ACCEPTED_DISPLACED_INVALID_ADDRESS : {
_r - > sw - > doAnythingWaitingForPeer ( p ) ;
Packet outp ( req - > source , _r - > identity . address ( ) , Packet : : VERB_OK ) ;
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
outp . append ( req - > helloPacketId ) ;
outp . append ( req - > helloTimestamp ) ;
outp . encrypt ( p - > cryptKey ( ) ) ;
outp . hmacSet ( p - > macKey ( ) ) ;
_r - > demarc - > send ( req - > localPort , req - > remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
} break ;
case Topology : : PEER_VERIFY_REJECTED_INVALID_IDENTITY : {
Packet outp ( req - > source , _r - > identity . address ( ) , Packet : : VERB_ERROR ) ;
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
outp . append ( req - > helloPacketId ) ;
outp . append ( ( unsigned char ) Packet : : ERROR_IDENTITY_INVALID ) ;
outp . encrypt ( p - > cryptKey ( ) ) ;
outp . hmacSet ( p - > macKey ( ) ) ;
_r - > demarc - > send ( req - > localPort , req - > remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
} break ;
case Topology : : PEER_VERIFY_REJECTED_DUPLICATE :
case Topology : : PEER_VERIFY_REJECTED_DUPLICATE_TRIAGED : {
Packet outp ( req - > source , _r - > identity . address ( ) , Packet : : VERB_ERROR ) ;
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
outp . append ( req - > helloPacketId ) ;
outp . append ( ( unsigned char ) Packet : : ERROR_IDENTITY_COLLISION ) ;
outp . encrypt ( p - > cryptKey ( ) ) ;
outp . hmacSet ( p - > macKey ( ) ) ;
_r - > demarc - > send ( req - > localPort , req - > remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
} break ;
}
delete req ;
}
void PacketDecoder : : _CBaddPeerFromWhois ( void * arg , const SharedPtr < Peer > & p , Topology : : PeerVerifyResult result )
{
switch ( result ) {
case Topology : : PEER_VERIFY_ACCEPTED_NEW :
case Topology : : PEER_VERIFY_ACCEPTED_ALREADY_HAVE :
case Topology : : PEER_VERIFY_ACCEPTED_DISPLACED_INVALID_ADDRESS :
( ( const RuntimeEnvironment * ) arg ) - > sw - > doAnythingWaitingForPeer ( p ) ;
break ;
default :
break ;
}
}
bool PacketDecoder : : _doERROR ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
try {
# ifdef ZT_TRACE
2013-07-12 02:06:25 +00:00
Packet : : Verb inReVerb = ( Packet : : Verb ) ( * this ) [ ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB ] ;
Packet : : ErrorCode errorCode = ( Packet : : ErrorCode ) ( * this ) [ ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE ] ;
TRACE ( " ERROR %s from %s(%s) in-re %s " , Packet : : errorString ( errorCode ) , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , Packet : : verbString ( inReVerb ) ) ;
2013-07-11 22:15:51 +00:00
# endif
// TODO (sorta):
// The fact is that the protocol works fine without error handling.
// The only error that really needs to be handled here is duplicate
// identity collision, which if it comes from a supernode should cause
// us to restart and regenerate a new identity.
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped ERROR from %s(%s): unexpected exception: %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 22:15:51 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped ERROR from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 21:52:04 +00:00
}
2013-07-11 22:15:51 +00:00
bool PacketDecoder : : _doHELLO ( const RuntimeEnvironment * _r )
2013-07-11 21:52:04 +00:00
{
try {
2013-07-12 02:06:25 +00:00
//unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
unsigned int vMajor = ( * this ) [ ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION ] ;
unsigned int vMinor = ( * this ) [ ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION ] ;
unsigned int vRevision = at < uint16_t > ( ZT_PROTO_VERB_HELLO_IDX_REVISION ) ;
uint64_t timestamp = at < uint64_t > ( ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP ) ;
Identity id ( * this , ZT_PROTO_VERB_HELLO_IDX_IDENTITY ) ;
2013-07-11 21:52:04 +00:00
SharedPtr < Peer > candidate ( new Peer ( _r - > identity , id ) ) ;
2013-07-11 22:15:51 +00:00
candidate - > setPathAddress ( _remoteAddress , false ) ;
2013-07-11 21:52:04 +00:00
// Initial sniff test
if ( id . address ( ) . isReserved ( ) ) {
2013-07-12 02:06:25 +00:00
TRACE ( " rejected HELLO from %s(%s): identity has reserved address " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
Packet outp ( source ( ) , _r - > identity . address ( ) , Packet : : VERB_ERROR ) ;
2013-07-11 21:52:04 +00:00
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
2013-07-12 02:06:25 +00:00
outp . append ( packetId ( ) ) ;
2013-07-11 21:52:04 +00:00
outp . append ( ( unsigned char ) Packet : : ERROR_IDENTITY_INVALID ) ;
outp . encrypt ( candidate - > cryptKey ( ) ) ;
outp . hmacSet ( candidate - > macKey ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > demarc - > send ( _localPort , _remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
return true ;
2013-07-11 21:52:04 +00:00
}
2013-07-12 02:06:25 +00:00
if ( id . address ( ) ! = source ( ) ) {
TRACE ( " rejected HELLO from %s(%s): identity is not for sender of packet (HELLO is a self-announcement) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
Packet outp ( source ( ) , _r - > identity . address ( ) , Packet : : VERB_ERROR ) ;
2013-07-11 21:52:04 +00:00
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
2013-07-12 02:06:25 +00:00
outp . append ( packetId ( ) ) ;
2013-07-11 21:52:04 +00:00
outp . append ( ( unsigned char ) Packet : : ERROR_INVALID_REQUEST ) ;
outp . encrypt ( candidate - > cryptKey ( ) ) ;
outp . hmacSet ( candidate - > macKey ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > demarc - > send ( _localPort , _remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
return true ;
2013-07-11 21:52:04 +00:00
}
// Is this a HELLO for a peer we already know? If so just update its
// packet receive stats and send an OK.
SharedPtr < Peer > existingPeer ( _r - > topology - > getPeer ( id . address ( ) ) ) ;
if ( ( existingPeer ) & & ( existingPeer - > identity ( ) = = id ) ) {
2013-07-12 02:06:25 +00:00
existingPeer - > onReceive ( _r , _localPort , _remoteAddress , hops ( ) , Packet : : VERB_HELLO , Utils : : now ( ) ) ;
existingPeer - > setRemoteVersion ( vMajor , vMinor , vRevision ) ;
2013-07-11 21:52:04 +00:00
2013-07-12 02:06:25 +00:00
Packet outp ( source ( ) , _r - > identity . address ( ) , Packet : : VERB_OK ) ;
2013-07-11 21:52:04 +00:00
outp . append ( ( unsigned char ) Packet : : VERB_HELLO ) ;
2013-07-12 02:06:25 +00:00
outp . append ( packetId ( ) ) ;
2013-07-11 21:52:04 +00:00
outp . append ( timestamp ) ;
outp . encrypt ( existingPeer - > cryptKey ( ) ) ;
outp . hmacSet ( existingPeer - > macKey ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > demarc - > send ( _localPort , _remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
return true ;
2013-07-11 21:52:04 +00:00
}
// Otherwise we call addPeer() and set up a callback to handle the verdict
_CBaddPeerFromHello_Data * arg = new _CBaddPeerFromHello_Data ;
2013-07-12 02:06:25 +00:00
arg - > renv = _r ;
arg - > source = source ( ) ;
arg - > remoteAddress = _remoteAddress ;
arg - > localPort = _localPort ;
2013-07-11 21:52:04 +00:00
arg - > vMajor = vMajor ;
arg - > vMinor = vMinor ;
arg - > vRevision = vRevision ;
2013-07-12 02:06:25 +00:00
arg - > helloPacketId = packetId ( ) ;
2013-07-11 21:52:04 +00:00
arg - > helloTimestamp = timestamp ;
2013-07-12 02:06:25 +00:00
_r - > topology - > addPeer ( candidate , & PacketDecoder : : _CBaddPeerFromHello , arg ) ;
2013-07-11 21:52:04 +00:00
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped HELLO from %s(%s): %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 22:15:51 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped HELLO from %s(%s): unexpected exception " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
bool PacketDecoder : : _doOK ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
try {
2013-07-12 02:06:25 +00:00
Packet : : Verb inReVerb = ( Packet : : Verb ) ( * this ) [ ZT_PROTO_VERB_OK_IDX_IN_RE_VERB ] ;
2013-07-11 22:15:51 +00:00
switch ( inReVerb ) {
2013-07-12 02:06:25 +00:00
case Packet : : VERB_HELLO : {
2013-07-11 22:15:51 +00:00
// OK from HELLO permits computation of latency.
2013-07-12 02:06:25 +00:00
unsigned int latency = std : : min ( ( unsigned int ) ( Utils : : now ( ) - at < uint64_t > ( ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP ) ) , ( unsigned int ) 0xffff ) ;
TRACE ( " %s(%s): OK(HELLO), latency: %u " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , latency ) ;
peer - > setLatency ( _remoteAddress , latency ) ;
} break ;
2013-07-11 22:15:51 +00:00
case Packet : : VERB_WHOIS :
// Right now we only query supernodes for WHOIS and only accept
// OK back from them. If we query other nodes, we'll have to
// do something to prevent WHOIS cache poisoning such as
// using the packet ID field in the OK packet to match with the
// original query. Technically we should be doing this anyway.
2013-07-12 02:06:25 +00:00
TRACE ( " %s(%s): OK(%s) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , Packet : : verbString ( inReVerb ) ) ;
if ( _r - > topology - > isSupernode ( source ( ) ) )
_r - > topology - > addPeer ( SharedPtr < Peer > ( new Peer ( _r - > identity , Identity ( * this , ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY ) ) ) , & PacketDecoder : : _CBaddPeerFromWhois , const_cast < void * > ( ( const void * ) _r ) ) ;
2013-07-11 22:15:51 +00:00
break ;
default :
2013-07-13 02:07:48 +00:00
//TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
2013-07-11 22:15:51 +00:00
break ;
}
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped OK from %s(%s): unexpected exception: %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 22:15:51 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped OK from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
bool PacketDecoder : : _doWHOIS ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
2013-07-12 02:06:25 +00:00
if ( payloadLength ( ) = = ZT_ADDRESS_LENGTH ) {
SharedPtr < Peer > p ( _r - > topology - > getPeer ( Address ( payload ( ) ) ) ) ;
2013-07-11 22:15:51 +00:00
if ( p ) {
2013-07-12 02:06:25 +00:00
Packet outp ( source ( ) , _r - > identity . address ( ) , Packet : : VERB_OK ) ;
2013-07-11 22:15:51 +00:00
outp . append ( ( unsigned char ) Packet : : VERB_WHOIS ) ;
2013-07-12 02:06:25 +00:00
outp . append ( packetId ( ) ) ;
2013-07-11 22:15:51 +00:00
p - > identity ( ) . serialize ( outp , false ) ;
outp . encrypt ( peer - > cryptKey ( ) ) ;
outp . hmacSet ( peer - > macKey ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > demarc - > send ( _localPort , _remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
TRACE ( " sent WHOIS response to %s for %s " , source ( ) . toString ( ) . c_str ( ) , Address ( payload ( ) ) . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
} else {
2013-07-12 02:06:25 +00:00
Packet outp ( source ( ) , _r - > identity . address ( ) , Packet : : VERB_ERROR ) ;
2013-07-11 22:15:51 +00:00
outp . append ( ( unsigned char ) Packet : : VERB_WHOIS ) ;
2013-07-12 02:06:25 +00:00
outp . append ( packetId ( ) ) ;
2013-07-11 22:15:51 +00:00
outp . append ( ( unsigned char ) Packet : : ERROR_NOT_FOUND ) ;
2013-07-12 02:06:25 +00:00
outp . append ( payload ( ) , ZT_ADDRESS_LENGTH ) ;
2013-07-11 22:15:51 +00:00
outp . encrypt ( peer - > cryptKey ( ) ) ;
outp . hmacSet ( peer - > macKey ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > demarc - > send ( _localPort , _remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
TRACE ( " sent WHOIS ERROR to %s for %s (not found) " , source ( ) . toString ( ) . c_str ( ) , Address ( payload ( ) ) . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped WHOIS from %s(%s): missing or invalid address " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
bool PacketDecoder : : _doRENDEZVOUS ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
try {
2013-07-12 02:06:25 +00:00
Address with ( field ( ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS , ZT_ADDRESS_LENGTH ) ) ;
2013-07-13 02:07:48 +00:00
SharedPtr < Peer > withPeer ( _r - > topology - > getPeer ( with ) ) ;
if ( withPeer ) {
2013-07-12 02:06:25 +00:00
unsigned int port = at < uint16_t > ( ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT ) ;
unsigned int addrlen = ( * this ) [ ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN ] ;
2013-07-11 22:15:51 +00:00
if ( ( port > 0 ) & & ( ( addrlen = = 4 ) | | ( addrlen = = 16 ) ) ) {
2013-07-12 02:06:25 +00:00
InetAddress atAddr ( field ( ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS , addrlen ) , addrlen , port ) ;
TRACE ( " RENDEZVOUS from %s says %s might be at %s, starting NAT-t " , source ( ) . toString ( ) . c_str ( ) , with . toString ( ) . c_str ( ) , atAddr . toString ( ) . c_str ( ) ) ;
2013-07-13 02:07:48 +00:00
_r - > sw - > contact ( withPeer , atAddr ) ;
2013-07-11 22:15:51 +00:00
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped corrupt RENDEZVOUS from %s(%s) (bad address or port) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " ignored RENDEZVOUS from %s(%s) to meet unknown peer %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , with . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped RENDEZVOUS from %s(%s): %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 22:15:51 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped RENDEZVOUS from %s(%s): unexpected exception " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
bool PacketDecoder : : _doFRAME ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
try {
2013-07-12 02:06:25 +00:00
SharedPtr < Network > network ( _r - > nc - > network ( at < uint64_t > ( ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID ) ) ) ;
2013-07-11 22:15:51 +00:00
if ( network ) {
2013-07-12 02:06:25 +00:00
if ( network - > isAllowed ( source ( ) ) ) {
unsigned int etherType = at < uint16_t > ( ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE ) ;
2013-07-11 22:15:51 +00:00
if ( ( etherType ! = ZT_ETHERTYPE_ARP ) & & ( etherType ! = ZT_ETHERTYPE_IPV4 ) & & ( etherType ! = ZT_ETHERTYPE_IPV6 ) ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped FRAME from %s: unsupported ethertype " , source ( ) . toString ( ) . c_str ( ) ) ;
} else if ( size ( ) > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD ) {
network - > tap ( ) . put ( source ( ) . toMAC ( ) , network - > tap ( ) . mac ( ) , etherType , data ( ) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD , size ( ) - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped FRAME from %s(%s): not a member of closed network %llu " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , network - > id ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped FRAME from %s(%s): network %llu unknown " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , at < uint64_t > ( ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID ) ) ;
2013-07-11 22:15:51 +00:00
}
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped FRAME from %s(%s): unexpected exception: %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 22:15:51 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped FRAME from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
bool PacketDecoder : : _doMULTICAST_LIKE ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
try {
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD ;
unsigned int numAccepted = 0 ;
2013-07-12 02:06:25 +00:00
uint64_t now = Utils : : now ( ) ;
2013-07-11 22:15:51 +00:00
// Iterate through 18-byte network,MAC,ADI tuples:
2013-07-12 02:06:25 +00:00
while ( ( ptr + 18 ) < = size ( ) ) {
uint64_t nwid = at < uint64_t > ( ptr ) ; ptr + = 8 ;
2013-07-11 22:15:51 +00:00
SharedPtr < Network > network ( _r - > nc - > network ( nwid ) ) ;
if ( network ) {
2013-07-12 02:06:25 +00:00
if ( network - > isAllowed ( source ( ) ) ) {
MAC mac ( field ( ptr , 6 ) ) ; ptr + = 6 ;
uint32_t adi = at < uint32_t > ( ptr ) ; ptr + = 4 ;
2013-07-13 02:07:48 +00:00
//TRACE("peer %s likes multicast group %s:%.8lx on network %llu",source().toString().c_str(),mac.toString().c_str(),(unsigned long)adi,nwid);
2013-07-12 02:06:25 +00:00
_r - > multicaster - > likesMulticastGroup ( nwid , MulticastGroup ( mac , adi ) , source ( ) , now ) ;
2013-07-11 22:15:51 +00:00
+ + numAccepted ;
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " ignored MULTICAST_LIKE from %s(%s): not a member of closed network %llu " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , nwid ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " ignored MULTICAST_LIKE from %s(%s): network %llu unknown or we are not a member " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , nwid ) ;
2013-07-11 22:15:51 +00:00
}
}
2013-07-12 02:06:25 +00:00
Packet outp ( source ( ) , _r - > identity . address ( ) , Packet : : VERB_OK ) ;
2013-07-11 22:15:51 +00:00
outp . append ( ( unsigned char ) Packet : : VERB_MULTICAST_LIKE ) ;
2013-07-12 02:06:25 +00:00
outp . append ( packetId ( ) ) ;
2013-07-11 22:15:51 +00:00
outp . append ( ( uint16_t ) numAccepted ) ;
outp . encrypt ( peer - > cryptKey ( ) ) ;
outp . hmacSet ( peer - > macKey ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > demarc - > send ( _localPort , _remoteAddress , outp . data ( ) , outp . size ( ) , - 1 ) ;
2013-07-11 22:15:51 +00:00
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 22:15:51 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_LIKE from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 22:15:51 +00:00
}
2013-07-12 02:06:25 +00:00
bool PacketDecoder : : _doMULTICAST_FRAME ( const RuntimeEnvironment * _r , const SharedPtr < Peer > & peer )
2013-07-11 22:15:51 +00:00
{
try {
2013-07-12 02:06:25 +00:00
SharedPtr < Network > network ( _r - > nc - > network ( at < uint64_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID ) ) ) ;
2013-07-11 22:15:51 +00:00
if ( network ) {
2013-07-12 02:06:25 +00:00
if ( network - > isAllowed ( source ( ) ) ) {
if ( size ( ) > ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD ) {
Address originalSubmitterAddress ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER_ADDRESS , ZT_ADDRESS_LENGTH ) ) ;
MAC fromMac ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC , 6 ) ) ;
MulticastGroup mg ( MAC ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_MAC , 6 ) ) , at < uint32_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ADI ) ) ;
unsigned int hops = ( * this ) [ ZT_PROTO_VERB_MULTICAST_FRAME_IDX_HOP_COUNT ] ;
unsigned int etherType = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE ) ;
unsigned int datalen = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LENGTH ) ;
unsigned int signaturelen = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SIGNATURE_LENGTH ) ;
unsigned char * dataAndSignature = field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD , datalen + signaturelen ) ;
2013-07-13 02:07:48 +00:00
uint64_t mccrc = Multicaster : : computeMulticastDedupCrc ( network - > id ( ) , fromMac , mg , etherType , dataAndSignature , datalen ) ;
uint64_t now = Utils : : now ( ) ;
bool isDuplicate = _r - > multicaster - > checkDuplicate ( mccrc , now ) ;
2013-07-11 22:15:51 +00:00
if ( originalSubmitterAddress = = _r - > identity . address ( ) ) {
// Technically should not happen, since the original submitter is
// excluded from consideration as a propagation recipient.
2013-07-12 02:06:25 +00:00
TRACE ( " dropped boomerang MULTICAST_FRAME received from %s(%s) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-23 17:23:55 +00:00
} else if ( ( ! isDuplicate ) | | ( _r - > topology - > amSupernode ( ) ) ) {
//
2013-07-11 22:15:51 +00:00
// If I am a supernode, I will repeatedly propagate duplicates. That's
// because supernodes are used to bridge sparse multicast groups. Non-
// supernodes will ignore duplicates completely.
2013-07-23 17:23:55 +00:00
//
// TODO: supernodes should keep a local bloom filter too and OR it with
// the bloom from the packet in order to pick different recipients each
// time a multicast returns to them for repropagation.
//
2013-07-11 22:15:51 +00:00
SharedPtr < Peer > originalSubmitter ( _r - > topology - > getPeer ( originalSubmitterAddress ) ) ;
if ( ! originalSubmitter ) {
TRACE ( " requesting WHOIS on original multicast frame submitter %s " , originalSubmitterAddress . toString ( ) . c_str ( ) ) ;
2013-07-12 02:06:25 +00:00
_r - > sw - > requestWhois ( originalSubmitterAddress ) ;
_step = DECODE_STEP_WAITING_FOR_ORIGINAL_SUBMITTER_LOOKUP ;
2013-07-23 17:23:55 +00:00
return false ; // try again if/when we get OK(WHOIS)
2013-07-12 02:06:25 +00:00
} else if ( Multicaster : : verifyMulticastPacket ( originalSubmitter - > identity ( ) , network - > id ( ) , fromMac , mg , etherType , dataAndSignature , datalen , dataAndSignature + datalen , signaturelen ) ) {
2013-07-13 02:07:48 +00:00
_r - > multicaster - > addToDedupHistory ( mccrc , now ) ;
2013-07-23 17:23:55 +00:00
// Even if we are a supernode, we still don't repeatedly inject
// duplicates into our own tap.
2013-07-11 22:15:51 +00:00
if ( ! isDuplicate )
2013-07-12 02:06:25 +00:00
network - > tap ( ) . put ( fromMac , mg . mac ( ) , etherType , dataAndSignature , datalen ) ;
if ( + + hops < ZT_MULTICAST_PROPAGATION_DEPTH ) {
2013-07-13 02:07:48 +00:00
Address upstream ( source ( ) ) ; // save this since we mangle it
2013-07-12 02:06:25 +00:00
Multicaster : : MulticastBloomFilter bloom ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_BLOOM_FILTER , ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES ) ) ;
SharedPtr < Peer > propPeers [ ZT_MULTICAST_PROPAGATION_BREADTH ] ;
unsigned int np = _r - > multicaster - > pickNextPropagationPeers (
2013-07-13 18:28:26 +00:00
* ( _r - > prng ) ,
2013-07-12 02:06:25 +00:00
* ( _r - > topology ) ,
network - > id ( ) ,
mg ,
originalSubmitterAddress ,
2013-07-13 02:07:48 +00:00
upstream ,
2013-07-12 02:06:25 +00:00
bloom ,
ZT_MULTICAST_PROPAGATION_BREADTH ,
propPeers ,
2013-07-13 02:07:48 +00:00
now ) ;
// In a bit of a hack, we re-use this packet to repeat it
// to our multicast propagation recipients. Afterwords we
// return true just to be sure this is the end of this
// packet's life cycle, since it is now mangled.
2013-07-12 02:06:25 +00:00
2013-07-12 20:40:59 +00:00
setSource ( _r - > identity . address ( ) ) ;
2013-07-12 02:06:25 +00:00
( * this ) [ ZT_PROTO_VERB_MULTICAST_FRAME_IDX_HOP_COUNT ] = hops ;
2013-07-12 21:21:23 +00:00
memcpy ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_BLOOM_FILTER , ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES ) , bloom . data ( ) , ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES ) ;
2013-07-12 02:06:25 +00:00
compress ( ) ;
for ( unsigned int i = 0 ; i < np ; + + i ) {
2013-07-23 17:23:55 +00:00
//TRACE("propagating multicast from original node %s: %s -> %s",originalSubmitterAddress.toString().c_str(),upstream.toString().c_str(),propPeers[i]->address().toString().c_str());
2013-07-12 02:06:25 +00:00
// Re-use this packet to re-send multicast frame to everyone
// downstream from us.
newInitializationVector ( ) ;
setDestination ( propPeers [ i ] - > address ( ) ) ;
_r - > sw - > send ( * this , true ) ;
}
2013-07-13 02:07:48 +00:00
return true ;
2013-07-12 02:06:25 +00:00
} else {
2013-07-23 17:23:55 +00:00
//TRACE("terminating MULTICAST_FRAME propagation from %s(%s): max depth reached",source().toString().c_str(),_remoteAddress.toString().c_str());
2013-07-12 02:06:25 +00:00
}
2013-07-11 22:15:51 +00:00
} else {
2013-07-12 02:06:25 +00:00
LOG ( " rejected MULTICAST_FRAME from %s(%s) due to failed signature check (claims original sender %s) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , originalSubmitterAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped redundant MULTICAST_FRAME from %s(%s) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_FRAME from %s(%s): invalid short packet " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_FRAME from %s(%s): not a member of closed network %llu " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , network - > id ( ) ) ;
2013-07-11 22:15:51 +00:00
}
} else {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_FRAME from %s(%s): network %llu unknown or we are not a member " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , at < uint64_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID ) ) ;
2013-07-11 22:15:51 +00:00
}
} catch ( std : : exception & ex ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_FRAME from %s(%s): unexpected exception: %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
2013-07-11 21:52:04 +00:00
} catch ( . . . ) {
2013-07-12 02:06:25 +00:00
TRACE ( " dropped MULTICAST_FRAME from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
2013-07-11 21:52:04 +00:00
}
2013-07-12 02:06:25 +00:00
return true ;
2013-07-11 20:19:06 +00:00
}
} // namespace ZeroTier