@ -605,7 +605,7 @@ bool IncomingPacket::_doP5_MULTICAST_FRAME(const RuntimeEnvironment *RR,const Sh
// If the sending peer is >=1.0.0, they only go to legacy peers. Otherwise they go to all
// peers.
const bool senderIsLegacy = ( ( peer - > remoteVersionMajor ( ) < 1 ) | | ( depth = = 0xbeef ) ) ;
const bool senderIsLegacy = ( ( peer - > remoteVersionMajor ( ) < 1 ) | | ( depth = = 0xbeef ) ) ; // magic number means "relayed on behalf of legacy peer"
const unsigned int limit = 128 ; // use a fairly generous limit since we want legacy peers to always work until they go away
std : : vector < Address > members ( RR - > mc - > getMembers ( nwid , dest , limit ) ) ;
@ -671,253 +671,6 @@ bool IncomingPacket::_doP5_MULTICAST_FRAME(const RuntimeEnvironment *RR,const Sh
} catch ( . . . ) {
TRACE ( " dropped P5_MULTICAST_FRAME from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
}
#if 0 // old code preserved below
try {
Address origin ( Address ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN ) , ZT_ADDRESS_LENGTH ) ) ;
SharedPtr < Peer > originPeer ( RR - > topology - > getPeer ( origin ) ) ;
if ( ! originPeer ) {
// We must have the origin's identity in order to authenticate a multicast
RR - > sw - > requestWhois ( origin ) ;
_step = DECODE_WAITING_FOR_MULTICAST_FRAME_ORIGINAL_SENDER_LOOKUP ; // causes processing to come back here
return false ;
}
// These fields in the packet are changed by each forwarder
unsigned int depth = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH ) ;
unsigned char * const fifo = field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO ) ;
unsigned char * const bloom = field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM ) ;
// These fields don't -- they're signed by the original sender
const unsigned int flags = ( * this ) [ ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS ] ;
const uint64_t nwid = at < uint64_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID ) ;
const uint16_t bloomNonce = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM_NONCE ) ;
const unsigned int prefixBits = ( * this ) [ ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX_BITS ] ;
const unsigned int prefix = ( * this ) [ ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX ] ;
const uint64_t guid = at < uint64_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GUID ) ;
const MAC sourceMac ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_SOURCE_MAC ) , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_SOURCE_MAC ) ;
const MulticastGroup dest ( MAC ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_MAC ) , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_MAC ) , at < uint32_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI ) ) ;
const unsigned int etherType = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE ) ;
const unsigned int frameLen = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME_LEN ) ;
const unsigned char * const frame = field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME , frameLen ) ;
const unsigned int signatureLen = at < uint16_t > ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen ) ;
const unsigned char * const signature = field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen + 2 , signatureLen ) ;
if ( ( ! sourceMac ) | | ( sourceMac . isMulticast ( ) ) ) {
TRACE ( " dropped MULTICAST_FRAME from %s(%s): invalid source MAC %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , sourceMac . toString ( ) . c_str ( ) ) ;
return true ;
}
SharedPtr < Network > network ( RR - > nc - > network ( nwid ) ) ;
SharedPtr < NetworkConfig > nconf ;
if ( network )
nconf = network - > config2 ( ) ;
/* Grab, verify, and learn certificate of network membership if any -- provided we are
* a member of this network . Note : we can do this before verification of the actual
* packet , since the certificate has its own separate signature . In other words a valid
* COM does not imply a valid multicast ; they are two separate things . The ability to
* include the COM with the multicast is a performance optimization to allow peers to
* distribute their COM along with their packets instead of as a separate transaction .
* This causes network memberships to start working faster . */
if ( ( ( flags & ZT_PROTO_VERB_MULTICAST_FRAME_FLAGS_HAS_MEMBERSHIP_CERTIFICATE ) ) & & ( network ) ) {
CertificateOfMembership originCom ( * this , ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen + 2 + signatureLen ) ;
Address comSignedBy ( originCom . signedBy ( ) ) ;
if ( ( originCom . networkId ( ) = = nwid ) & & ( comSignedBy = = network - > controller ( ) ) ) {
SharedPtr < Peer > comSigningPeer ( RR - > topology - > getPeer ( comSignedBy ) ) ;
if ( ! comSigningPeer ) {
// Technically this should never happen because the COM should be signed by
// the master for this network (in current usage) and we ought to already have
// that cached. But handle it anyway.
RR - > sw - > requestWhois ( comSignedBy ) ;
_step = DECODE_WAITING_FOR_MULTICAST_FRAME_ORIGINAL_SENDER_LOOKUP ; // causes processing to come back here
return false ;
} else if ( originCom . verify ( comSigningPeer - > identity ( ) ) ) {
// The certificate is valid so learn it. As explained above this does not
// imply validation of the multicast. That happens later. Look for a call
// to network->isAllowed().
network - > addMembershipCertificate ( originCom ) ;
} else {
// Go ahead and drop the multicast though if the COM was invalid, since this
// obviously signifies a problem.
LOG ( " dropped MULTICAST_FRAME from %s(%s): included COM failed authentication check " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
return true ;
}
} else {
// Go ahead and drop the multicast here too, since this also ought never to
// happen and certainly indicates a problem.
LOG ( " dropped MULTICAST_FRAME from %s(%s): included COM is not for this network " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
return true ;
}
}
// Check the multicast frame's signature to verify that its original sender is
// who it claims to be.
const unsigned int signedPartLen = ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION ) + frameLen ;
if ( ! originPeer - > identity ( ) . verify ( field ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION , signedPartLen ) , signedPartLen , signature , signatureLen ) ) {
LOG ( " dropped MULTICAST_FRAME from %s(%s): failed signature verification, claims to be from %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , origin . toString ( ) . c_str ( ) ) ;
return true ;
}
// Security check to prohibit multicasts that are really Ethernet unicasts...
// otherwise people could do weird things like multicast out a TCP SYN.
if ( ! dest . mac ( ) . isMulticast ( ) ) {
LOG ( " dropped MULTICAST_FRAME from %s(%s): %s is not a multicast/broadcast address " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , dest . mac ( ) . toString ( ) . c_str ( ) ) ;
return true ;
}
// At this point the frame is basically valid, so we can call it a receive
peer - > receive ( RR , _fromSock , _remoteAddress , hops ( ) , packetId ( ) , Packet : : VERB_MULTICAST_FRAME , 0 , Packet : : VERB_NOP , Utils : : now ( ) ) ;
// This gets updated later in most cases but start with the global limit.
unsigned int maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH ;
if ( ( origin = = RR - > identity . address ( ) ) | | ( RR - > mc - > deduplicate ( nwid , guid ) ) ) {
// This is a boomerang or a duplicate of a multicast we've already seen. Ordinary
// nodes drop these, while supernodes will keep propagating them since they can
// act as bridges between sparse multicast networks more than once.
if ( ! RR - > topology - > amSupernode ( ) ) {
TRACE ( " dropped MULTICAST_FRAME from %s(%s): duplicate " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
return true ;
}
} else {
// If we are actually a member of this network (will just about always
// be the case unless we're a supernode), check to see if we should
// inject the packet. This also gives us an opportunity to check things
// like multicast bandwidth constraints.
if ( ( network ) & & ( nconf ) ) {
// Learn real maxDepth from netconf
maxDepth = std : : min ( ( unsigned int ) ZT_MULTICAST_GLOBAL_MAX_DEPTH , nconf - > multicastDepth ( ) ) ;
if ( ! maxDepth )
maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH ;
if ( ! network - > isAllowed ( origin ) ) {
// Papers, please...
Packet outp ( source ( ) , RR - > identity . address ( ) , Packet : : VERB_ERROR ) ;
outp . append ( ( unsigned char ) Packet : : VERB_MULTICAST_FRAME ) ;
outp . append ( packetId ( ) ) ;
outp . append ( ( unsigned char ) Packet : : ERROR_NEED_MEMBERSHIP_CERTIFICATE ) ;
outp . append ( nwid ) ;
outp . armor ( peer - > key ( ) , true ) ;
_fromSock - > send ( _remoteAddress , outp . data ( ) , outp . size ( ) ) ;
TRACE ( " dropped MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , nwid , origin . toString ( ) . c_str ( ) ) ;
return true ;
}
if ( MAC ( origin , network - > id ( ) ) ! = sourceMac ) {
if ( ! nconf - > permitsBridging ( origin ) ) {
TRACE ( " dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , nwid , sourceMac . toString ( ) . c_str ( ) , origin . toString ( ) . c_str ( ) ) ;
return true ;
}
network - > learnBridgeRoute ( sourceMac , origin ) ;
}
if ( ! nconf - > permitsEtherType ( etherType ) ) {
TRACE ( " dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed " , source ( ) . toString ( ) . c_str ( ) , nwid , _remoteAddress . toString ( ) . c_str ( ) , etherType ) ;
return true ;
}
if ( ! network - > updateAndCheckMulticastBalance ( origin , dest , frameLen ) ) {
// Rate limits can only be checked by members of this network, but
// there should be enough of them that over-limit multicasts get
// their propagation aborted.
TRACE ( " dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , origin . toString ( ) . c_str ( ) ) ;
return true ;
}
network - > tapPut ( sourceMac , dest . mac ( ) , etherType , frame , frameLen ) ;
}
}
// Depth of 0xffff means "do not forward." Check first since
// incrementing this would integer overflow a 16-bit int.
if ( depth = = 0xffff ) {
TRACE ( " not forwarding MULTICAST_FRAME from %s(%s): depth == 0xffff (do not forward) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
return true ;
}
// Check if graph traversal depth has exceeded configured maximum.
if ( + + depth > maxDepth ) {
TRACE ( " not forwarding MULTICAST_FRAME from %s(%s): max propagation depth reached " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
return true ;
}
// Update depth in packet with new incremented value
setAt ( ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH , ( uint16_t ) depth ) ;
// New FIFO with room for one extra, since head will be next hop
unsigned char newFifo [ ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO + ZT_ADDRESS_LENGTH ] ;
unsigned char * newFifoPtr = newFifo ;
unsigned char * const newFifoEnd = newFifo + sizeof ( newFifo ) ;
// Copy old FIFO into new buffer, terminating at first NULL address
for ( unsigned char * f = fifo , * const fifoEnd = ( fifo + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO ) ; f ! = fifoEnd ; ) {
unsigned char * nf = newFifoPtr ;
unsigned char * e = nf + ZT_ADDRESS_LENGTH ;
unsigned char * ftmp = f ;
unsigned char zeroCheckMask = 0 ;
while ( nf ! = e )
zeroCheckMask | = ( * ( nf + + ) = * ( ftmp + + ) ) ;
if ( zeroCheckMask ) {
f = ftmp ;
newFifoPtr = nf ;
} else break ;
}
// Add any other next hops we know about to FIFO
Multicaster : : AddToPropagationQueue appender (
& newFifoPtr ,
newFifoEnd ,
bloom ,
bloomNonce ,
origin ,
prefixBits ,
prefix ,
RR - > topology ,
Utils : : now ( ) ) ;
if ( nconf ) {
for ( std : : set < Address > : : const_iterator ab ( nconf - > activeBridges ( ) . begin ( ) ) ; ab ! = nconf - > activeBridges ( ) . end ( ) ; + + ab ) {
if ( ! appender ( * ab ) )
break ;
}
}
RR - > mc - > getNextHops ( nwid , dest , appender ) ;
// Zero-terminate new FIFO if not completely full. We pad the remainder with
// zeroes because this improves data compression ratios.
while ( newFifoPtr ! = newFifoEnd )
* ( newFifoPtr + + ) = ( unsigned char ) 0 ;
// First element in newFifo[] is next hop
Address nextHop ( newFifo , ZT_ADDRESS_LENGTH ) ;
if ( ( ! nextHop ) & & ( ! RR - > topology - > amSupernode ( ) ) ) {
SharedPtr < Peer > supernode ( RR - > topology - > getBestSupernode ( & origin , 1 , true ) ) ;
if ( supernode )
nextHop = supernode - > address ( ) ;
}
if ( ( ! nextHop ) | | ( nextHop = = RR - > identity . address ( ) ) ) { // check against our addr is a sanity check
//TRACE("not forwarding MULTICAST_FRAME from %s(%s): no next hop",source().toString().c_str(),_remoteAddress.toString().c_str());
return true ;
}
// The rest of newFifo[] goes back into the packet
memcpy ( fifo , newFifo + ZT_ADDRESS_LENGTH , ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO ) ;
// Send to next hop, reusing this packet as scratch space
newInitializationVector ( ) ;
setDestination ( nextHop ) ;
setSource ( RR - > identity . address ( ) ) ;
compress ( ) ; // note: bloom filters and empty FIFOs are highly compressable!
RR - > sw - > send ( * this , true ) ;
return true ;
} catch ( std : : exception & ex ) {
TRACE ( " dropped MULTICAST_FRAME from %s(%s): unexpected exception: %s " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) , ex . what ( ) ) ;
} catch ( . . . ) {
TRACE ( " dropped MULTICAST_FRAME from %s(%s): unexpected exception: (unknown) " , source ( ) . toString ( ) . c_str ( ) , _remoteAddress . toString ( ) . c_str ( ) ) ;
}
# endif
return true ;
}