| 
					
				 | 
			
			
				@@ -554,6 +554,8 @@ bool IncomingPacket::_doP5_MULTICAST_FRAME(const RuntimeEnvironment *RR,const Sh 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const unsigned int signatureLen = at<uint16_t>(ZT_PROTO_VERB_P5_MULTICAST_FRAME_IDX_FRAME + frameLen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (origin == RR->identity.address()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			Mutex::Lock _l(p5MulticastDedupBuffer_m); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if (!p5MulticastDedupBufferPtr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				memset(p5MulticastDedupBuffer,0,sizeof(p5MulticastDedupBuffer)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -566,6 +568,32 @@ bool IncomingPacket::_doP5_MULTICAST_FRAME(const RuntimeEnvironment *RR,const Sh 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			p5MulticastDedupBuffer[p5MulticastDedupBufferPtr++ % 1024] = guid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		SharedPtr<Network> network(RR->nc->network(nwid)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (network) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if ((flags & ZT_PROTO_VERB_P5_MULTICAST_FRAME_FLAGS_HAS_MEMBERSHIP_CERTIFICATE) != 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				CertificateOfMembership com; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				com.deserialize(*this,ZT_PROTO_VERB_P5_MULTICAST_FRAME_IDX_FRAME + frameLen + 2 + signatureLen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (com.hasRequiredFields()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					network->addMembershipCertificate(com,false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (!network->isAllowed(origin)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				SharedPtr<Peer> originPeer(RR->topology->getPeer(origin)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (originPeer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					_sendErrorNeedCertificate(RR,originPeer,nwid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} else if ((frameLen > 0)&&(frameLen <= 2800)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (!dest.mac().isMulticast()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if ((!sourceMac)||(sourceMac.isMulticast())||(sourceMac == network->mac())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (sourceMac != MAC(origin,nwid)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (network->permitsBridging(origin)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						network->learnBridgeRoute(sourceMac,origin); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} else return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		peer->receive(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_P5_MULTICAST_FRAME,0,Packet::VERB_NOP,Utils::now()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (RR->topology->amSupernode()) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -577,12 +605,14 @@ bool IncomingPacket::_doP5_MULTICAST_FRAME(const RuntimeEnvironment *RR,const Sh 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			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)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SharedPtr<Peer> lpp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			setAt(ZT_PROTO_VERB_P5_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH,(uint16_t)0xffff); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			setSource(RR->identity.address()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			compress(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			for(std::vector<Address>::iterator lp(members.begin());lp!=members.end();++lp) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				SharedPtr<Peer> lpp(RR->topology->getPeer(*lp)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (!senderIsLegacy) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					lpp = RR->topology->getPeer(*lp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if ( (*lp != origin) && (*lp != peer->address()) && ((senderIsLegacy) || (!lpp) || (lpp->remoteVersionMajor() < 1)) ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					newInitializationVector(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					setDestination(*lp); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -605,35 +635,6 @@ bool IncomingPacket::_doP5_MULTICAST_FRAME(const RuntimeEnvironment *RR,const Sh 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				sn->send(RR,data(),size(),Utils::now()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		SharedPtr<Network> network(RR->nc->network(nwid)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if (network) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if ((flags & ZT_PROTO_VERB_P5_MULTICAST_FRAME_FLAGS_HAS_MEMBERSHIP_CERTIFICATE)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				CertificateOfMembership com; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen + 2 + signatureLen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (com.hasRequiredFields()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					network->addMembershipCertificate(com,false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (!network->isAllowed(origin)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				_sendErrorNeedCertificate(RR,peer,network->id()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if ((frameLen > 0)&&(frameLen <= 2800)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (!dest.mac().isMulticast()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if ((!sourceMac)||(sourceMac.isMulticast())||(sourceMac == network->mac())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (sourceMac != MAC(origin,network->id())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if (network->permitsBridging(origin)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						network->learnBridgeRoute(sourceMac,origin); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} else return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} catch (std::exception &ex) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		TRACE("dropped P5_MULTICAST_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} catch ( ... ) { 
			 |