Exemple #1
0
void CNatSocket::SendBufferedSegment(sTransferBufferEntry* BufferEntry)
{
	// NOTE: This function is invoked from a *different* thread! But all places where it is called are (and must be) locked already

/*	T_TRACE("%s: Segment Size=%u; uSequenceNr=%u, ConnAck=%d",__FUNCTION__,
		BufferEntry ? BufferEntry->uSize : 0, BufferEntry ? BufferEntry->uSequenceNr : 0,
		m_dwConnAskNumber);
*/
	if(m_ShutDown & 0x02)
	{
		return; // shocket is shuting down
	}

	uchar *pBuffer=NULL;
	int size=0;

	if(BufferEntry)
	{
		//VC-fengwen on 2008/01/04 <begin> :
		if (0 == BufferEntry->uSendCount)
		{
			m_uPendingWindowSize += BufferEntry->uSize;
			m_unackSet.insert(BufferEntry->uSequenceNr);
		}
		//VC-fengwen on 2008/01/04 <end> :

		BufferEntry->uSendCount++;
		BufferEntry->uSendTime = ::GetTickCount();

		size = BufferEntry->uSize + 4+4;// segment size + 4 bytes sequence number, there are also 2 bytes ed2k opcodes thiere are irrleevant here
		pBuffer = new uchar[size];

		PokeUInt32(pBuffer, m_dwConnAskNumber);
		PokeUInt32(pBuffer+4, BufferEntry->uSequenceNr); // segment sequence number
		// Note: we don't need to write the length as the UDP protocol already take care about the size
		memcpy(pBuffer+8,BufferEntry->pBuffer,BufferEntry->uSize);
	}
	else // if the last recived Advertised Window size is 0 and we have datas in buffer we ping with empty segments to get a new window size
			// Note: regular TCP sendy a minimal data segment != 0 expecting it to be dropped is window is still 0
	{
		size = 4+4;
		pBuffer = new uchar[8];

		PokeUInt32(pBuffer, m_dwConnAskNumber);
		PokeUInt32(pBuffer+4, 0);
	}

	// send packet

	if(size && pBuffer)
	{
		SendPacket(OP_NAT_DATA, pBuffer, size);

		//T_TRACE("Window Size %d", m_snd.wnd);
	}

	delete [] pBuffer;
}
Exemple #2
0
void CSocks4StateMachine::process_send_command_request(bool entry)
{
	if (entry) {
		// Prepare the request command buffer
		m_buffer[0] = SOCKS4_VERSION;
		switch (m_proxyCommand) {
		case PROXY_CMD_CONNECT:
			m_buffer[1] = SOCKS4_CMD_CONNECT;
			break;
			
		case PROXY_CMD_BIND:
			m_buffer[1] = SOCKS4_CMD_BIND;
			break;
			
		case PROXY_CMD_UDP_ASSOCIATE:
			m_ok = false;
			return;
			break;
		}
		RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
		// Special processing for SOCKS4a
		switch (m_proxyData.m_proxyType) {
		case PROXY_SOCKS4a:
			PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
			break;
		case PROXY_SOCKS4:
		default:
			PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
			break;
		}
		// Common processing for SOCKS4/SOCKS4a
		unsigned int offsetUser = 8;
		unsigned char lenUser = m_proxyData.m_userName.Len();
		memcpy(m_buffer + offsetUser, 
			unicode2char(m_proxyData.m_userName), lenUser);
		m_buffer[offsetUser + lenUser] = 0;
		// Special processing for SOCKS4a
		switch (m_proxyData.m_proxyType) {
		case PROXY_SOCKS4a: {
			unsigned int offsetDomain = offsetUser + lenUser + 1;
			unsigned char lenDomain = m_peerAddress->Hostname().Len();
			memcpy(m_buffer + offsetDomain, 
				unicode2char(m_peerAddress->Hostname()), lenDomain);
			m_buffer[offsetDomain + lenDomain] = 0;
			m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
			break;
		}
		case PROXY_SOCKS4:
		default:
			m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
			break;
		}
		// Send the command packet
		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
	}
}
Exemple #3
0
wxDatagramSocket &CDatagramSocketProxy::SendTo(
	wxIPaddress &addr, const void* buf, wxUint32 nBytes )
{
	wxMutexLocker lock(m_socketLocker);
	m_lastUDPOperation = UDP_OPERATION_SEND_TO;
	m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
	if (m_proxyTCPSocket.GetUseProxy()) {
		if (m_udpSocketOk) {
			m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV;	// Reserved
			m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV;	// Reserved
			m_proxyTCPSocket.GetBuffer()[2] = 0;		// FRAG
			m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
			PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
			RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
			memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
			nBytes += PROXY_UDP_OVERHEAD_IPV4;
			wxDatagramSocket::SendTo(
				m_proxyTCPSocket.GetProxyBoundAddress(),
				m_proxyTCPSocket.GetBuffer(), nBytes);
			// Uncomment here to see the buffer contents on console
			// DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
		}
	} else {
		wxDatagramSocket::SendTo(addr, buf, nBytes);
	}
	
	return *this;
}
Exemple #4
0
void CECTag::InitInt(uint64 data)
{
	if (data <= 0xFF) {
		m_dataType = EC_TAGTYPE_UINT8;
		m_dataLen = 1;
	} else if (data <= 0xFFFF) {
		m_dataType = EC_TAGTYPE_UINT16;
		m_dataLen = 2;
	} else if (data <= 0xFFFFFFFF) {
		m_dataType = EC_TAGTYPE_UINT32;
		m_dataLen = 4;
	} else {
		m_dataType = EC_TAGTYPE_UINT64;
		m_dataLen = 8;
	}

	NewData();

	switch (m_dataType) {
		case EC_TAGTYPE_UINT8:
			PokeUInt8( m_tagData, (uint8) data );
			break;
		case EC_TAGTYPE_UINT16:
			PokeUInt16( m_tagData, wxUINT16_SWAP_ALWAYS((uint16) data ));
			break;
		case EC_TAGTYPE_UINT32:
			PokeUInt32( m_tagData, wxUINT32_SWAP_ALWAYS((uint32) data ));
			break;
		case EC_TAGTYPE_UINT64:
			PokeUInt64( m_tagData, wxUINT64_SWAP_ALWAYS(data) );
			break;
	}
}
Exemple #5
0
void CSocks5StateMachine::process_send_command_request(bool entry)
{
	if (entry) {
		// Prepare the request command buffer
		m_buffer[0] = SOCKS5_VERSION;
		switch (m_proxyCommand) {
		case PROXY_CMD_CONNECT:
			m_buffer[1] = SOCKS5_CMD_CONNECT;
			break;
			
		case PROXY_CMD_BIND:
			m_buffer[1] = SOCKS5_CMD_BIND;
			break;
			
		case PROXY_CMD_UDP_ASSOCIATE:
			m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
			break;
		}
		m_buffer[2] = SOCKS5_RSV;
		m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
		PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
		RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
		
		// Send the command packet
		m_packetLenght = 10;
		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
	}
}
int CEncryptedDatagramSocket::EncryptSendServer(uint8_t** ppbyBuf, int nBufLen, uint32_t dwBaseKey)
{
	wxASSERT( thePrefs::IsServerCryptLayerUDPEnabled() );
	wxASSERT( dwBaseKey != 0 );

	uint16_t nRandomKeyPart = GetRandomUint16();

	uint8_t achKeyData[7];
	PokeUInt32(achKeyData, dwBaseKey);
	achKeyData[4] = MAGICVALUE_UDP_CLIENTSERVER;
	PokeUInt16(achKeyData + 5, nRandomKeyPart);
	MD5Sum md5(achKeyData, sizeof(achKeyData));
	CRC4EncryptableBuffer sendbuffer;
	sendbuffer.SetKey(md5, true);

	// create the semi random byte encryption header
	uint8_t bySemiRandomNotProtocolMarker = 0;
	int i;

	for (i = 0; i < 128; i++) {
		bySemiRandomNotProtocolMarker = GetRandomUint8();
		if (bySemiRandomNotProtocolMarker != OP_EDONKEYPROT) { // not allowed values
			break;
		}
	}

	if (i >= 128) {
		// either we have _real_ bad luck or the randomgenerator is a bit messed up
		wxFAIL;
		bySemiRandomNotProtocolMarker = 0x01;
	}

	uint8_t byPadLen = 0;			// padding disabled for UDP currently
	uint32_t nCryptedLen = nBufLen + byPadLen + CRYPT_HEADER_WITHOUTPADDING;
	uint8_t* pachCryptedBuffer = new uint8_t[nCryptedLen];

	pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker;
	PokeUInt16(pachCryptedBuffer + 1, nRandomKeyPart);

	uint32_t dwMagicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_SERVER);
	sendbuffer.RC4Crypt((uint8_t*)&dwMagicValue, pachCryptedBuffer + 3, 4);

	sendbuffer.RC4Crypt((uint8_t*)&byPadLen, pachCryptedBuffer + 7, 1);

	for (int j = 0; j < byPadLen; j++){
		uint8_t byRand = (uint8_t)rand();	// they actually don't really need to be random, but it doesn't hurt either
		sendbuffer.RC4Crypt((uint8_t*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1);
	}
	sendbuffer.RC4Crypt(*ppbyBuf, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, nBufLen);
	delete[] *ppbyBuf;
	*ppbyBuf = pachCryptedBuffer;

	theStats::AddUpOverheadCrypt(nCryptedLen - nBufLen);
	return nCryptedLen;
}
int CEncryptedDatagramSocket::DecryptReceivedServer(uint8_t* pbyBufIn, int nBufLen, uint8_t **ppbyBufOut, uint32_t dwBaseKey, uint32_t /*dbgIP*/)
{
	int nResult = nBufLen;
	*ppbyBufOut = pbyBufIn;

	if (nResult <= CRYPT_HEADER_WITHOUTPADDING || !thePrefs::IsServerCryptLayerUDPEnabled() || dwBaseKey == 0) {
		return nResult;
	}

	if(pbyBufIn[0] == OP_EDONKEYPROT) {
		return nResult; // no encrypted packet (see description on top)
	}

	// might be an encrypted packet, try to decrypt
	uint8_t achKeyData[7];
	PokeUInt32(achKeyData, dwBaseKey);
	achKeyData[4] = MAGICVALUE_UDP_SERVERCLIENT;
	memcpy(achKeyData + 5, pbyBufIn + 1, 2); // random key part sent from remote server

	CRC4EncryptableBuffer receivebuffer;
	MD5Sum md5(achKeyData, sizeof(achKeyData));
	receivebuffer.SetKey(md5,true);

	uint32_t dwValue;
	receivebuffer.RC4Crypt(pbyBufIn + 3, (uint8_t*)&dwValue, sizeof(dwValue));
	ENDIAN_SWAP_I_32(dwValue);
	if (dwValue == MAGICVALUE_UDP_SYNC_SERVER) {
		// yup this is an encrypted packet
		//DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from ServerIP: %s"), ipstr(dbgIP)) );
		uint8_t byPadLen;
		receivebuffer.RC4Crypt(pbyBufIn + 7, (uint8_t*)&byPadLen, 1);
		byPadLen &= 15;
		nResult -= CRYPT_HEADER_WITHOUTPADDING;

		if (nResult <= byPadLen) {
			//DebugLogError(_T("Invalid obfuscated UDP packet from ServerIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dbgIP), byPadLen);
			return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
		}

		if (byPadLen > 0) {
			receivebuffer.RC4Crypt(NULL, NULL, byPadLen);
		}

		nResult -= byPadLen;
		*ppbyBufOut = pbyBufIn + (nBufLen - nResult);
		receivebuffer.RC4Crypt((uint8_t*)*ppbyBufOut, (uint8_t*)*ppbyBufOut, nResult);

		theStats::AddDownOverheadCrypt(nBufLen - nResult);
		return nResult; // done
	} else {
		//DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from ServerIP: %s"), ipstr(dbgIP));
		return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
	}
}
Exemple #8
0
void CKnownFileList::AddCancelledFileID(const uchar* hash){
	if (thePrefs.IsRememberingCancelledFiles()){
		if (m_dwCancelledFilesSeed == 0) {
			m_dwCancelledFilesSeed = (GetRandomUInt32() % 0xFFFFFFFE) + 1;
		}
		uchar pachSeedHash[20];
		PokeUInt32(pachSeedHash, m_dwCancelledFilesSeed);
		md4cpy(pachSeedHash + 4, hash);
		MD5Sum md5(pachSeedHash, sizeof(pachSeedHash));
		md4cpy(pachSeedHash, md5.GetRawHash()); 
		m_mapCancelledFiles.SetAt(CSKey(pachSeedHash), 1);	
	}
}
Exemple #9
0
bool CKnownFileList::IsCancelledFileByID(const uchar* hash) const
{
	if (thePrefs.IsRememberingCancelledFiles()){
		uchar pachSeedHash[20];
		PokeUInt32(pachSeedHash, m_dwCancelledFilesSeed);
		md4cpy(pachSeedHash + 4, hash);
		MD5Sum md5(pachSeedHash, sizeof(pachSeedHash));
		md4cpy(pachSeedHash, md5.GetRawHash()); 

		int dwDummy;
		if (m_mapCancelledFiles.Lookup(CSKey(pachSeedHash), dwDummy)){
			return true;
		}
	}
	return false;
}
void CEncryptedStreamSocket::SetConnectionEncryption(bool bEnabled, const uint8_t* pTargetClientHash, bool bServerConnection)
{
	if (m_StreamCryptState != ECS_UNKNOWN && m_StreamCryptState != ECS_NONE) {
		if (!m_StreamCryptState == ECS_NONE || bEnabled) {
			wxFAIL;
		}
		return;
	}

	if (bEnabled && pTargetClientHash != NULL && !bServerConnection) {
		m_StreamCryptState = ECS_PENDING;
		// create obfuscation keys, see on top for key format

		// use the crypt random generator
		m_nRandomKeyPart = GetRandomUint32();

		uint8 achKeyData[21];
		md4cpy(achKeyData, pTargetClientHash);
		PokeUInt32(achKeyData + 17, m_nRandomKeyPart);

		achKeyData[16] = MAGICVALUE_REQUESTER;
		MD5Sum md5(achKeyData, sizeof(achKeyData));
		m_pfiSendBuffer.SetKey(md5);

		achKeyData[16] = MAGICVALUE_SERVER;
		md5.Calculate(achKeyData, sizeof(achKeyData));
		m_pfiReceiveBuffer.SetKey(md5);

	} else if (bServerConnection && bEnabled) {
		//printf("->Server crypt\n");
		m_bServerCrypt = true;
		m_StreamCryptState = ECS_PENDING_SERVER;
	} else {
		wxASSERT( !bEnabled );
		m_StreamCryptState = ECS_NONE;
	}
}
// Encrypt packet. Key used:
// clientHashOrKadID != NULL					-> clientHashOrKadID
// clientHashOrKadID == NULL && kad && receiverVerifyKey != 0	-> receiverVerifyKey
// else								-> ASSERT
int CEncryptedDatagramSocket::EncryptSendClient(uint8_t **buf, int bufLen, const uint8_t *clientHashOrKadID, bool kad, uint32_t receiverVerifyKey, uint32_t senderVerifyKey)
{
	wxASSERT(theApp->GetPublicIP() != 0 || kad);
	wxASSERT(thePrefs::IsClientCryptLayerSupported());
	wxASSERT(clientHashOrKadID != NULL || receiverVerifyKey != 0);
	wxASSERT((receiverVerifyKey == 0 && senderVerifyKey == 0) || kad);

	uint8_t padLen = 0;			// padding disabled for UDP currently
	const uint32_t cryptHeaderLen = padLen + CRYPT_HEADER_WITHOUTPADDING + (kad ? 8 : 0);
	uint32_t cryptedLen = bufLen + cryptHeaderLen;
	uint8_t *cryptedBuffer = new uint8_t[cryptedLen];
	bool kadRecvKeyUsed = false;

	uint16_t randomKeyPart = GetRandomUint16();
	CRC4EncryptableBuffer sendbuffer;
	MD5Sum md5;
	if (kad) {
		if ((clientHashOrKadID == NULL || CMD4Hash(clientHashOrKadID).IsEmpty()) && receiverVerifyKey != 0) {
			kadRecvKeyUsed = true;
			uint8_t keyData[6];
			PokeUInt32(keyData, receiverVerifyKey);
			PokeUInt16(keyData+4, randomKeyPart);
			md5.Calculate(keyData, sizeof(keyData));
			//DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by ReceiverKey (%u)"), nReceiverVerifyKey) );
		}
		else if (clientHashOrKadID != NULL && !CMD4Hash(clientHashOrKadID).IsEmpty()) {
			uint8_t keyData[18];
			md4cpy(keyData, clientHashOrKadID);
			PokeUInt16(keyData+16, randomKeyPart);
			md5.Calculate(keyData, sizeof(keyData));
			//DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by Hash/NodeID %s"), md4str(pachClientHashOrKadID)) );
		}
		else {
			delete [] cryptedBuffer;
			wxFAIL;
			return bufLen;
		}
	} else {
		uint8_t keyData[23];
		md4cpy(keyData, clientHashOrKadID);
		PokeUInt32(keyData+16, theApp->GetPublicIP());
		PokeUInt16(keyData+21, randomKeyPart);
		keyData[20] = MAGICVALUE_UDP;
		md5.Calculate(keyData, sizeof(keyData));
	}

	sendbuffer.SetKey(md5, true);

	// create the semi random byte encryption header
	uint8_t semiRandomNotProtocolMarker = 0;
	int i;
	for (i = 0; i < 128; i++) {
		semiRandomNotProtocolMarker = GetRandomUint8();
		semiRandomNotProtocolMarker = kad ? (semiRandomNotProtocolMarker & 0xFE) : (semiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit
		if (kad) {
			// set the ed2k/kad and nodeid/recvkey markerbit
			semiRandomNotProtocolMarker = kadRecvKeyUsed ? ((semiRandomNotProtocolMarker & 0xFE) | 0x02) : (semiRandomNotProtocolMarker & 0xFC);
		} else {
			// set the ed2k/kad marker bit
			semiRandomNotProtocolMarker = (semiRandomNotProtocolMarker | 0x01);
		}

		bool bOk = false;
		switch (semiRandomNotProtocolMarker) { // not allowed values
			case OP_EMULEPROT:
			case OP_KADEMLIAPACKEDPROT:
			case OP_KADEMLIAHEADER:
			case OP_UDPRESERVEDPROT1:
			case OP_UDPRESERVEDPROT2:
			case OP_PACKEDPROT:
				break;
			default:
				bOk = true;
		}

		if (bOk) {
			break;
		}
	}

	if (i >= 128) {
		// either we have _real_ bad luck or the randomgenerator is a bit messed up
		wxFAIL;
		semiRandomNotProtocolMarker = 0x01;
	}

	cryptedBuffer[0] = semiRandomNotProtocolMarker;
	PokeUInt16(cryptedBuffer + 1, randomKeyPart);

	uint32_t magicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_CLIENT);
	sendbuffer.RC4Crypt((uint8_t*)&magicValue, cryptedBuffer + 3, 4);
	sendbuffer.RC4Crypt((uint8_t*)&padLen, cryptedBuffer + 7, 1);

	for (int j = 0; j < padLen; j++) {
		uint8_t byRand = (uint8_t)rand();	// they actually don't really need to be random, but it doesn't hurt either
		sendbuffer.RC4Crypt((uint8_t*)&byRand, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1);
	}

	if (kad) {
		ENDIAN_SWAP_I_32(receiverVerifyKey);
		ENDIAN_SWAP_I_32(senderVerifyKey);
		sendbuffer.RC4Crypt((uint8_t*)&receiverVerifyKey, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + padLen, 4);
		sendbuffer.RC4Crypt((uint8_t*)&senderVerifyKey, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + padLen + 4, 4);
	}

	sendbuffer.RC4Crypt(*buf, cryptedBuffer + cryptHeaderLen, bufLen);
	delete [] *buf;
	*buf = cryptedBuffer;

	theStats::AddUpOverheadCrypt(cryptedLen - bufLen);
	return cryptedLen;
}
int CEncryptedDatagramSocket::DecryptReceivedClient(uint8_t *bufIn, int bufLen, uint8_t **bufOut, uint32_t ip, uint32_t *receiverVerifyKey, uint32_t *senderVerifyKey)
{
	int result = bufLen;
	*bufOut = bufIn;

	if (receiverVerifyKey == NULL || senderVerifyKey == NULL) {
		wxFAIL;
		return result;
	}

	*receiverVerifyKey = 0;
	*senderVerifyKey = 0;

	if (result <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/) {
		return result;
	}

	switch (bufIn[0]) {
		case OP_EMULEPROT:
		case OP_KADEMLIAPACKEDPROT:
		case OP_KADEMLIAHEADER:
		case OP_UDPRESERVEDPROT1:
		case OP_UDPRESERVEDPROT2:
		case OP_PACKEDPROT:
			return result; // no encrypted packet (see description on top)
		default:
			;
	}

	// might be an encrypted packet, try to decrypt
	CRC4EncryptableBuffer receivebuffer;
	uint32_t value = 0;
	// check the marker bit which type this packet could be and which key to test first, this is only an indicator since old clients have it set random
	// see the header for marker bits explanation
	uint8_t currentTry = ((bufIn[0] & 0x03) == 3) ? 1 : (bufIn[0] & 0x03);
	uint8_t tries;
	if (Kademlia::CKademlia::GetPrefs() == NULL) {
		// if kad never run, no point in checking anything except for ed2k encryption
		tries = 1;
		currentTry = 1;
	} else {
		tries = 3;
	}
	bool kad = false;
	do {
		receivebuffer.FullReset();
		tries--;
		MD5Sum md5;

		if (currentTry == 0) {
			// kad packet with NodeID as key
			kad = true;
			if (Kademlia::CKademlia::GetPrefs()) {
				uint8_t keyData[18];
				Kademlia::CKademlia::GetPrefs()->GetKadID().StoreCryptValue((uint8_t *)&keyData);
				memcpy(keyData + 16, bufIn + 1, 2); // random key part sent from remote client
				md5.Calculate(keyData, sizeof(keyData));
			}
		} else if (currentTry == 1) {
			// ed2k packet
			kad = false;
			uint8_t keyData[23];
			md4cpy(keyData, thePrefs::GetUserHash().GetHash());
			keyData[20] = MAGICVALUE_UDP;
			PokeUInt32(keyData + 16, ip);
			memcpy(keyData + 21, bufIn + 1, 2); // random key part sent from remote client
			md5.Calculate(keyData, sizeof(keyData));
		} else if (currentTry == 2) {
			// kad packet with ReceiverKey as key
			kad = true;
			if (Kademlia::CKademlia::GetPrefs()) {
				uint8_t keyData[6];
				PokeUInt32(keyData, Kademlia::CPrefs::GetUDPVerifyKey(ip));
				memcpy(keyData + 4, bufIn + 1, 2); // random key part sent from remote client
				md5.Calculate(keyData, sizeof(keyData));
			}
		} else {
			wxFAIL;
		}

		receivebuffer.SetKey(md5, true);
		receivebuffer.RC4Crypt(bufIn + 3, (uint8_t*)&value, sizeof(value));
		ENDIAN_SWAP_I_32(value);

		currentTry = (currentTry + 1) % 3;
	} while (value != MAGICVALUE_UDP_SYNC_CLIENT && tries > 0); // try to decrypt as ed2k as well as kad packet if needed (max 3 rounds)

	if (value == MAGICVALUE_UDP_SYNC_CLIENT) {
		// yup this is an encrypted packet
//		// debugoutput notices
//		// the following cases are "allowed" but shouldn't happen given that there is only our implementation yet
//		if (bKad && (pbyBufIn[0] & 0x01) != 0)
//			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, ed2k bit)"), ipstr(dwIP));
//		else if (bKad && !bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) != 0)
//			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, nodeid key, recvkey bit)"), ipstr(dwIP));
//		else if (bKad && bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) == 0)
//			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, recvkey key, nodeid bit)"), ipstr(dwIP));

		uint8_t padLen;
		receivebuffer.RC4Crypt(bufIn + 7, (uint8_t*)&padLen, 1);
		result -= CRYPT_HEADER_WITHOUTPADDING;

		if (result <= padLen) {
			//DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen);
			return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk
		}

		if (padLen > 0) {
			receivebuffer.RC4Crypt(NULL, NULL, padLen);
		}

		result -= padLen;

		if (kad) {
			if (result <= 8) {
				//DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP));
				return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk;
			}
			// read the verify keys
			receivebuffer.RC4Crypt(bufIn + CRYPT_HEADER_WITHOUTPADDING + padLen, (uint8_t*)receiverVerifyKey, 4);
			receivebuffer.RC4Crypt(bufIn + CRYPT_HEADER_WITHOUTPADDING + padLen + 4, (uint8_t*)senderVerifyKey, 4);
			ENDIAN_SWAP_I_32(*receiverVerifyKey);
			ENDIAN_SWAP_I_32(*senderVerifyKey);
			result -= 8;
		}

		*bufOut = bufIn + (bufLen - result);

		receivebuffer.RC4Crypt((uint8_t*)*bufOut, (uint8_t*)*bufOut, result);
		theStats::AddDownOverheadCrypt(bufLen - result);
		return result; // done
	} else {
		//DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP));
		return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk
	}
}
Exemple #13
0
bool CKnownFileList::LoadCancelledFiles(){
// cancelled.met Format: <Header 1 = CANCELLED_HEADER><Version 1 = CANCELLED_VERSION><Seed 4><Count 4>[<HashHash 16><TagCount 1>[Tags TagCount] Count]
	if (!thePrefs.IsRememberingCancelledFiles())
		return true;
	CString fullpath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR);
	fullpath.Append(CANCELLED_MET_FILENAME);
	CSafeBufferedFile file;
	CFileException fexp;
	if (!file.Open(fullpath,CFile::modeRead|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyWrite, &fexp)){
		if (fexp.m_cause != CFileException::fileNotFound){
			CString strError(_T("Failed to load ") CANCELLED_MET_FILENAME _T(" file"));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			LogError(LOG_STATUSBAR, _T("%s"), strError);
		}
		return false;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);
	uchar ucHash[16];
	try {
		bool bOldVersion = false;
		uint8 header = file.ReadUInt8();
		if (header != CANCELLED_HEADER){
			if (header == CANCELLED_HEADER_OLD){
				bOldVersion = true;
				DebugLog(_T("Deprecated version of cancelled.met found, converting to new version"));
			}
			else{
				file.Close();
				return false;
			}
		}
		uint8 byVersion = 0;
		if (!bOldVersion){
			byVersion = file.ReadUInt8();
			if (byVersion > CANCELLED_VERSION){
				file.Close();
				return false;
			}

			m_dwCancelledFilesSeed = file.ReadUInt32();
		}
		if (m_dwCancelledFilesSeed == 0) {
			ASSERT( bOldVersion || file.GetLength() <= 10 );
			m_dwCancelledFilesSeed = (GetRandomUInt32() % 0xFFFFFFFE) + 1;
		}

		UINT RecordsNumber = file.ReadUInt32();
		for (UINT i = 0; i < RecordsNumber; i++) {
			file.ReadHash16(ucHash);
			uint8 nCount = file.ReadUInt8();
			// for compatibility with future versions which may add more data than just the hash
			for (UINT j = 0; j < nCount; j++) {
				CTag tag(&file, false);
			}
			if (bOldVersion){
				// convert old real hash to new hashash
				uchar pachSeedHash[20];
				PokeUInt32(pachSeedHash, m_dwCancelledFilesSeed);
				md4cpy(pachSeedHash + 4, ucHash);
				MD5Sum md5(pachSeedHash, sizeof(pachSeedHash));
				md4cpy(ucHash, md5.GetRawHash()); 
			}
			m_mapCancelledFiles.SetAt(CSKey(ucHash), 1);
		}
		file.Close();
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile)
			LogError(LOG_STATUSBAR, GetResString(IDS_ERR_CONFIGCORRUPT), CANCELLED_MET_FILENAME);
		else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer, ARRSIZE(buffer));
			LogError(LOG_STATUSBAR, GetResString(IDS_ERR_FAILEDTOLOAD), CANCELLED_MET_FILENAME, buffer);
		}
		error->Delete();
		return false;
	}
	return true;
}
bool CClientUDPSocket::ProcessPacket(const BYTE* packet, uint16 size, uint8 opcode, uint32 ip, uint16 port)
{
	switch(opcode)
	{
		case OP_REASKCALLBACKUDP:
		{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ReaskCallbackUDP", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			CUpDownClient* buddy = theApp.clientlist->GetBuddy();
			if( buddy )
			{
				if( size < 17 || buddy->socket == NULL )
					break;
				if (!md4cmp(packet, buddy->GetBuddyID()))
				{
					PokeUInt32(const_cast<BYTE*>(packet)+10, ip);
					PokeUInt16(const_cast<BYTE*>(packet)+14, port);
					Packet* response = new Packet(OP_EMULEPROT);
					response->opcode = OP_REASKCALLBACKTCP;
					response->pBuffer = new char[size];
					memcpy(response->pBuffer, packet+10, size-10);
					response->size = size-10;
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__ReaskCallbackTCP", buddy);
					theStats.AddUpDataOverheadFileRequest(response->size);
					buddy->socket->SendPacket(response);
				}
			}
			break;
		}
		case OP_REASKFILEPING:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CSafeMemFile data_in(packet, size);
			uchar reqfilehash[16];
			data_in.ReadHash16(reqfilehash);
			CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(reqfilehash);
			if (!reqfile)
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0) {
					DebugRecv("OP_ReaskFilePing", NULL, reqfilehash, ip);
					DebugSend("OP__FileNotFound", NULL);
				}

				Packet* response = new Packet(OP_FILENOTFOUND,0,OP_EMULEPROT);
				theStats.AddUpDataOverheadFileRequest(response->size);
				SendPacket(response, ip, port);
				break;
			}
			CUpDownClient* sender = theApp.uploadqueue->GetWaitingClientByIP_UDP(ip, port);
			if (sender)
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP_ReaskFilePing", sender, reqfilehash);

				//Make sure we are still thinking about the same file
				if (md4cmp(reqfilehash, sender->GetUploadFileID()) == 0)
				{
					sender->AddAskedCount();
					sender->SetLastUpRequest();
					//I messed up when I first added extended info to UDP
					//I should have originally used the entire ProcessExtenedInfo the first time.
					//So now I am forced to check UDPVersion to see if we are sending all the extended info.
					//For now on, we should not have to change anything here if we change
					//anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
					//Update extended info. 
					if (sender->GetUDPVersion() > 3)
					{
						sender->ProcessExtendedInfo(&data_in, reqfile);
					}
					//Update our complete source counts.
					else if (sender->GetUDPVersion() > 2)
					{
						uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
						uint16 nCompleteCountNew = data_in.ReadUInt16();
						sender->SetUpCompleteSourcesCount(nCompleteCountNew);
						if (nCompleteCountLast != nCompleteCountNew)
						{
							reqfile->UpdatePartsInfo();
						}
					}
					CSafeMemFile data_out(128);
					if(sender->GetUDPVersion() > 3)
					{
						if (reqfile->IsPartFile())
							((CPartFile*)reqfile)->WritePartStatus(&data_out);
						else
							data_out.WriteUInt16(0);
					}
					data_out.WriteUInt16(theApp.uploadqueue->GetWaitingPosition(sender));
					if (thePrefs.GetDebugClientUDPLevel() > 0)
						DebugSend("OP__ReaskAck", sender);
					Packet* response = new Packet(&data_out, OP_EMULEPROT);
					response->opcode = OP_REASKACK;
					theStats.AddUpDataOverheadFileRequest(response->size);
					theApp.clientudp->SendPacket(response, ip, port);
				}
				else
				{
					DebugLogError(_T("Client UDP socket; ReaskFilePing; reqfile does not match"));
					TRACE(_T("reqfile:         %s\n"), DbgGetFileInfo(reqfile->GetFileHash()));
					TRACE(_T("sender->GetRequestFile(): %s\n"), sender->GetRequestFile() ? DbgGetFileInfo(sender->GetRequestFile()->GetFileHash()) : _T("(null)"));
				}
			}
			else
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugRecv("OP_ReaskFilePing", NULL, reqfilehash, ip);

				if (((uint32)theApp.uploadqueue->GetWaitingUserCount() + 50) > thePrefs.GetQueueSize())
				{
					if (thePrefs.GetDebugClientUDPLevel() > 0)
						DebugSend("OP__QueueFull", NULL);
					Packet* response = new Packet(OP_QUEUEFULL,0,OP_EMULEPROT);
					theStats.AddUpDataOverheadFileRequest(response->size);
					SendPacket(response, ip, port);
				}
			}
			break;
		}
		case OP_QUEUEFULL:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_QueueFull", sender, NULL, ip);
			if (sender){
				sender->SetRemoteQueueFull(true);
				sender->UDPReaskACK(0);
			}
			break;
		}
		case OP_REASKACK:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_ReaskAck", sender, NULL, ip);
			if (sender){
				CSafeMemFile data_in(packet, size);
				if ( sender->GetUDPVersion() > 3 )
				{
					sender->ProcessFileStatus(true, &data_in, sender->GetRequestFile());
				}
				uint16 nRank = data_in.ReadUInt16();
				sender->SetRemoteQueueFull(false);
				sender->UDPReaskACK(nRank);
				sender->AddAskedCountDown();
			}
			break;
		}
		case OP_FILENOTFOUND:
		{
			theStats.AddDownDataOverheadFileRequest(size);
			CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_FileNotFound", sender, NULL, ip);
			if (sender){
				sender->UDPReaskFNF(); // may delete 'sender'!
				sender = NULL;
			}
			break;
		}
		case OP_PORTTEST:
		{
			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugRecv("OP_PortTest", NULL, NULL, ip);
			theStats.AddDownDataOverheadOther(size);
			if (size == 1){
				if (packet[0] == 0x12){
					bool ret = theApp.listensocket->SendPortTestReply('1', true);
					AddDebugLogLine(true, _T("UDP Portcheck packet arrived - ACK sent back (status=%i)"), ret);
				}
			}
			break;
		}
		default:
			theStats.AddDownDataOverheadOther(size);
			if (thePrefs.GetDebugClientUDPLevel() > 0)
			{
				CUpDownClient* sender = theApp.downloadqueue->GetDownloadClientByIP_UDP(ip, port);
				Debug(_T("Unknown client UDP packet: host=%s:%u (%s) opcode=0x%02x  size=%u\n"), ipstr(ip), port, sender ? sender->DbgGetClientInfo() : _T(""), opcode, size);
			}
			return false;
	}
	return true;
}
void CServerList::ServerStats()
{
	// Update the server list even if we are connected to Kademlia only. The idea is for both networks to keep 
	// each other up to date.. Kad network can get you back into the ED2K network.. And the ED2K network can get 
	// you back into the Kad network..
	if (theApp.IsConnected() && theApp.serverconnect->IsUDPSocketAvailable() && list.GetCount() > 0)
	{
		CServer* ping_server = GetNextStatServer();
		if (!ping_server)
			return;

		uint32 tNow = (uint32)time(NULL);
		const CServer* test = ping_server;
        while (ping_server->GetLastPingedTime() != 0 && (tNow - ping_server->GetLastPingedTime()) < UDPSERVSTATREASKTIME)
		{
			ping_server = GetNextStatServer();
			if (ping_server == test)
				return;
		}
		// IP-filter: We do not need to IP-filter any servers here, even dynIP-servers are not
		// needed to get filtered here. See also comments in 'CServerSocket::ConnectTo'.
		if (ping_server->GetFailedCount() >= thePrefs.GetDeadServerRetries()) {
			//Xman
			// Mighty Knife: Static server handling
			// Static servers can be prevented from being removed from the list.
			if ((!ping_server->IsStaticMember()) || (!thePrefs.GetDontRemoveStaticServers())) {
				theApp.emuledlg->serverwnd->serverlistctrl.RemoveServer(ping_server);
				return;
			}
			//Xman end
		}
		srand(tNow);
		ping_server->SetRealLastPingedTime(tNow); // this is not used to calcualte the next ping, but only to ensure a minimum delay for premature pings
		if (!ping_server->GetCryptPingReplyPending() && (tNow - ping_server->GetLastPingedTime()) >= UDPSERVSTATREASKTIME && theApp.GetPublicIP() != 0 && thePrefs.IsServerCryptLayerUDPEnabled()){
			// we try a obfsucation ping first and wait 20 seconds for an answer
			// if it doesn'T get responsed, we don't count it as error but continue with a normal ping
			ping_server->SetCryptPingReplyPending(true);
			uint32 nPacketLen = 4 + (uint8)(rand() % 16); // max padding 16 bytes
			BYTE* pRawPacket = new BYTE[nPacketLen];
			uint32 dwChallenge = (rand() << 17) | (rand() << 2) | (rand() & 0x03);
			if (dwChallenge == 0)
				dwChallenge++;
			PokeUInt32(pRawPacket, dwChallenge);
			for (uint32 i = 4; i < nPacketLen; i++) // fillung up the remaining bytes with random data
				pRawPacket[i] = (uint8)rand();

			ping_server->SetChallenge(dwChallenge);
			ping_server->SetLastPinged(GetTickCount());
			ping_server->SetLastPingedTime((tNow - (uint32)UDPSERVSTATREASKTIME) + 20); // give it 20 seconds to respond
			
			if (thePrefs.GetDebugServerUDPLevel() > 0)
				Debug(_T(">>> Sending OP__GlobServStatReq (obfuscated) to server %s:%u\n"), ping_server->GetAddress(), ping_server->GetPort());

			theStats.AddUpDataOverheadServer(nPacketLen);
			theApp.serverconnect->SendUDPPacket(NULL, ping_server, true, ping_server->GetPort() + 12, pRawPacket, nPacketLen);
		}
		else if (ping_server->GetCryptPingReplyPending() || theApp.GetPublicIP() == 0 || !thePrefs.IsServerCryptLayerUDPEnabled()){
			// our obfsucation ping request was not answered, so probably the server doesn'T supports obfuscation
			// continue with a normal request
			if (ping_server->GetCryptPingReplyPending() && thePrefs.IsServerCryptLayerUDPEnabled())
				DEBUG_ONLY(DebugLog(_T("CryptPing failed for server %s"), ping_server->GetListName()));
			else if (thePrefs.IsServerCryptLayerUDPEnabled())
				DEBUG_ONLY(DebugLog(_T("CryptPing skipped because our public IP is unknown for server %s"), ping_server->GetListName()));
			
			ping_server->SetCryptPingReplyPending(false);			
			Packet* packet = new Packet(OP_GLOBSERVSTATREQ, 4);
			uint32 uChallenge = 0x55AA0000 + GetRandomUInt16();
			ping_server->SetChallenge(uChallenge);
			PokeUInt32(packet->pBuffer, uChallenge);
			ping_server->SetLastPinged(GetTickCount());
			ping_server->SetLastPingedTime(tNow - (rand() % HR2S(1)));
			ping_server->AddFailedCount();
			theApp.emuledlg->serverwnd->serverlistctrl.RefreshServer(ping_server);
			if (thePrefs.GetDebugServerUDPLevel() > 0)
				Debug(_T(">>> Sending OP__GlobServStatReq (not obfuscated) to server %s:%u\n"), ping_server->GetAddress(), ping_server->GetPort());
			theStats.AddUpDataOverheadServer(packet->size);
			theApp.serverconnect->SendUDPPacket(packet, ping_server, true);
		}
		else
			ASSERT( false );
	}
}
int CEncryptedDatagramSocket::DecryptReceivedClient(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwIP, uint32* nReceiverVerifyKey, uint32* nSenderVerifyKey) const{
	int nResult = nBufLen;
	*ppbyBufOut = pbyBufIn;
	
	if (nReceiverVerifyKey == NULL || nSenderVerifyKey == NULL){
		ASSERT( false );
		return nResult;
	}
	
	*nReceiverVerifyKey = 0;
	*nSenderVerifyKey = 0;

	if (nResult <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/)
		return nResult;	

	switch (pbyBufIn[0]){
		case OP_EMULEPROT:
		case OP_KADEMLIAPACKEDPROT:
		case OP_KADEMLIAHEADER:
		case OP_UDPRESERVEDPROT1:
		case OP_UDPRESERVEDPROT2:
		case OP_PACKEDPROT:
			return nResult; // no encrypted packet (see description on top)
	}

	// might be an encrypted packet, try to decrypt
	RC4_Key_Struct keyReceiveKey;
	uint32 dwValue = 0;
	// check the marker bit which type this packet could be and which key to test first, this is only an indicator since old clients have it set random
	// see the header for marker bits explanation
	byte byCurrentTry = ((pbyBufIn[0] & 0x03) == 3) ? 1 : (pbyBufIn[0] & 0x03); 
	byte byTries;
	if (Kademlia::CKademlia::GetPrefs() == NULL) {
		// if kad never run, no point in checking anything except for ed2k encryption
		byTries = 1;
		byCurrentTry = 1;
	}
	else
		byTries = 3;
	bool bKadRecvKeyUsed = false;
	bool bKad = false;
	do{
		byTries--;
		MD5Sum md5;
		if (byCurrentTry == 0) {
			// kad packet with NodeID as key
			bKad = true;
			bKadRecvKeyUsed = false;
			if (Kademlia::CKademlia::GetPrefs()) {
				uchar achKeyData[18];
				memcpy(achKeyData, Kademlia::CKademlia::GetPrefs()->GetKadID().GetData(), 16);
				memcpy(achKeyData + 16, pbyBufIn + 1, 2); // random key part sent from remote client
				md5.Calculate(achKeyData, sizeof(achKeyData));
			}
		}
		else if (byCurrentTry == 1) {
			// ed2k packet
			bKad = false;
			bKadRecvKeyUsed = false;
			uchar achKeyData[23];
			md4cpy(achKeyData, thePrefs.GetUserHash());
			achKeyData[20] = MAGICVALUE_UDP;
			memcpy(achKeyData + 16, &dwIP, 4);
			memcpy(achKeyData + 21, pbyBufIn + 1, 2); // random key part sent from remote client
			md5.Calculate(achKeyData, sizeof(achKeyData));
		}
		else if (byCurrentTry == 2) {
			// kad packet with ReceiverKey as key
			bKad = true;
			bKadRecvKeyUsed = true;
			if (Kademlia::CKademlia::GetPrefs()) {
				uchar achKeyData[6];
				PokeUInt32(achKeyData, Kademlia::CPrefs::GetUDPVerifyKey(dwIP));
				memcpy(achKeyData + 4, pbyBufIn + 1, 2); // random key part sent from remote client
				md5.Calculate(achKeyData, sizeof(achKeyData));
			}
		}
		else
			ASSERT( false );

		RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true);
		RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey);
		byCurrentTry = (byCurrentTry + 1) % 3;
	} while (dwValue != MAGICVALUE_UDP_SYNC_CLIENT && byTries > 0); // try to decrypt as ed2k as well as kad packet if needed (max 3 rounds)
	
	if (dwValue == MAGICVALUE_UDP_SYNC_CLIENT){
		// yup this is an encrypted packet
		// debugoutput notices
		// the following cases are "allowed" but shouldn't happen given that there is only our implementation yet
		if (bKad && (pbyBufIn[0] & 0x01) != 0)
			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, ed2k bit)"), ipstr(dwIP));
		else if (bKad && !bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) != 0)
			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, nodeid key, recvkey bit)"), ipstr(dwIP));
		else if (bKad && bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) == 0)
			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, recvkey key, nodeid bit)"), ipstr(dwIP));

		uint8 byPadLen;
		RC4Crypt(pbyBufIn + 7, (uchar*)&byPadLen, 1, &keyReceiveKey);
		nResult -= CRYPT_HEADER_WITHOUTPADDING;
		if (nResult <= byPadLen){
			DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen);
			return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
		}
		if (byPadLen > 0)
			RC4Crypt(NULL, NULL, byPadLen, &keyReceiveKey);
		nResult -= byPadLen;

		if (bKad){
			if (nResult <= 8){
				DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP));
				return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk;
			}
			// read the verify keys
			RC4Crypt(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen, (uchar*)nReceiverVerifyKey, 4, &keyReceiveKey);
			RC4Crypt(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 4, (uchar*)nSenderVerifyKey, 4, &keyReceiveKey);
			nResult -= 8;
		}
		*ppbyBufOut = pbyBufIn + (nBufLen - nResult);
		RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey);
		//Xman
		// Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter-
		/*
		theStats.AddDownDataOverheadCrypt(nBufLen - nResult);
		*/
		theApp.pBandWidthControl->AddeMuleInObfuscation(nBufLen - nResult);
		//Xman end
		//DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s, Key: %s, RKey: %u, SKey: %u"), ipstr(dwIP), bKad ? (bKadRecvKeyUsed ? _T("ReceiverKey") : _T("NodeID")) : _T("UserHash")
		//	, nReceiverVerifyKey != 0 ? *nReceiverVerifyKey : 0, nSenderVerifyKey != 0 ? *nSenderVerifyKey : 0) );
		return nResult; // done
	}
	else{
		DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s, Possible RecvKey: %u"), ipstr(dwIP), Kademlia::CPrefs::GetUDPVerifyKey(dwIP));
		return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
	}
}
// Encrypt packet. Key used:
// pachClientHashOrKadID != NULL									-> pachClientHashOrKadID
// pachClientHashOrKadID == NULL && bKad && nReceiverVerifyKey != 0 -> nReceiverVerifyKey
// else																-> ASSERT
int CEncryptedDatagramSocket::EncryptSendClient(uchar** ppbyBuf, int nBufLen, const uchar* pachClientHashOrKadID, bool bKad, uint32 nReceiverVerifyKey, uint32 nSenderVerifyKey) const{
	ASSERT( theApp.GetPublicIP() != 0 || bKad );
	ASSERT( thePrefs.IsClientCryptLayerSupported() );
	ASSERT( pachClientHashOrKadID != NULL || nReceiverVerifyKey != 0 );
	ASSERT( (nReceiverVerifyKey == 0 && nSenderVerifyKey == 0) || bKad );

	uint8 byPadLen = 0;			// padding disabled for UDP currently
	const uint32 nCryptHeaderLen = byPadLen + CRYPT_HEADER_WITHOUTPADDING + (bKad ? 8 : 0);
	
	uint32 nCryptedLen = nBufLen + nCryptHeaderLen;
	uchar* pachCryptedBuffer = new uchar[nCryptedLen];
	bool bKadRecKeyUsed = false;
	
	uint16 nRandomKeyPart = (uint16)cryptRandomGen.GenerateWord32(0x0000, 0xFFFF);
	MD5Sum md5;
	if (bKad){
		if ((pachClientHashOrKadID == NULL || isnulmd4(pachClientHashOrKadID)) && nReceiverVerifyKey != 0) {
			bKadRecKeyUsed = true;
			uchar achKeyData[6];
			PokeUInt32(achKeyData, nReceiverVerifyKey);
			PokeUInt16(achKeyData+4, nRandomKeyPart);
			md5.Calculate(achKeyData, sizeof(achKeyData));
			//DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by ReceiverKey (%u)"), nReceiverVerifyKey) );  
		}
		else if (pachClientHashOrKadID != NULL && !isnulmd4(pachClientHashOrKadID)) {
			uchar achKeyData[18];
			md4cpy(achKeyData, pachClientHashOrKadID);
			PokeUInt16(achKeyData+16, nRandomKeyPart);
			md5.Calculate(achKeyData, sizeof(achKeyData));
			//DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by Hash/NodeID %s"), md4str(pachClientHashOrKadID)) );  
		}
		else {
			ASSERT( false );
			delete[] pachCryptedBuffer;
			return nBufLen;
		}
	}
	else{
		uchar achKeyData[23];
		md4cpy(achKeyData, pachClientHashOrKadID);
		uint32 dwIP = theApp.GetPublicIP();
		memcpy(achKeyData+16, &dwIP, 4);
		memcpy(achKeyData+21, &nRandomKeyPart, 2);
		achKeyData[20] = MAGICVALUE_UDP;
		md5.Calculate(achKeyData, sizeof(achKeyData));
	}
	RC4_Key_Struct keySendKey;
	RC4CreateKey(md5.GetRawHash(), 16, &keySendKey, true);

	// create the semi random byte encryption header
	uint8 bySemiRandomNotProtocolMarker = 0;
	int i;
	for (i = 0; i < 128; i++){
		bySemiRandomNotProtocolMarker = cryptRandomGen.GenerateByte();
		bySemiRandomNotProtocolMarker = bKad ? (bySemiRandomNotProtocolMarker & 0xFE) : (bySemiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit
		if (bKad)
			bySemiRandomNotProtocolMarker = bKadRecKeyUsed ? ((bySemiRandomNotProtocolMarker & 0xFE) | 0x02) : (bySemiRandomNotProtocolMarker & 0xFC); // set the ed2k/kad and nodeid/reckey markerbit
		else
			bySemiRandomNotProtocolMarker = (bySemiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit
		
		bool bOk = false;
		switch (bySemiRandomNotProtocolMarker){ // not allowed values
			case OP_EMULEPROT:
			case OP_KADEMLIAPACKEDPROT:
			case OP_KADEMLIAHEADER:
			case OP_UDPRESERVEDPROT1:
			case OP_UDPRESERVEDPROT2:
			case OP_PACKEDPROT:
				break;
			default:
				bOk = true;
		}
		if (bOk)
			break;
	}
	if (i >= 128){
		// either we have _really_ bad luck or the randomgenerator is a bit messed up
		ASSERT( false );
		bySemiRandomNotProtocolMarker = 0x01;
	}

	uint32 dwMagicValue = MAGICVALUE_UDP_SYNC_CLIENT;
	pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker;
	memcpy(pachCryptedBuffer + 1, &nRandomKeyPart, 2);
	RC4Crypt((uchar*)&dwMagicValue, pachCryptedBuffer + 3, 4, &keySendKey);
	RC4Crypt((uchar*)&byPadLen, pachCryptedBuffer + 7, 1, &keySendKey);

	for (int j = 0; j < byPadLen; j++){
		uint8 byRand = (uint8)rand();	// they actually dont really need to be random, but it doesn't hurts either
		RC4Crypt((uchar*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1, &keySendKey);
	}

	if (bKad){
		RC4Crypt((uchar*)&nReceiverVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, 4, &keySendKey);
		RC4Crypt((uchar*)&nSenderVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 4, 4, &keySendKey);
	}

	RC4Crypt(*ppbyBuf, pachCryptedBuffer + nCryptHeaderLen, nBufLen, &keySendKey);
	delete[] *ppbyBuf;
	*ppbyBuf = pachCryptedBuffer;

	//Xman
	// Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter-
	/*
	theStats.AddUpDataOverheadCrypt(nCryptedLen - nBufLen);
	*/
	theApp.pBandWidthControl->AddeMuleOutObfuscationUDP(nCryptedLen - nBufLen);
	//Xman end

	return nCryptedLen;
}
void CServerList::ServerStats()
{
	// Update the server list even if we are connected to Kademlia only. The idea is for both networks to keep 
	// each other up to date.. Kad network can get you back into the ED2K network.. And the ED2K network can get 
	// you back into the Kad network..
	if (theApp.IsConnected() && theApp.serverconnect->IsUDPSocketAvailable() && list.GetCount() > 0)
	{
		CServer* ping_server = GetNextStatServer();
		if (!ping_server)
			return;

		uint32 tNow = (uint32)time(NULL);
		const CServer* test = ping_server;
        while (ping_server->GetLastPingedTime() != 0 && (tNow - ping_server->GetLastPingedTime()) < UDPSERVSTATREASKTIME)
		{
			ping_server = GetNextStatServer();
			if (ping_server == test)
				return;
		}
		if (ping_server->GetFailedCount() >= thePrefs.GetDeadServerRetries()) {
			// Mighty Knife: Static server handling
			// Static servers can be prevented from being removed from the list.
			if ((!ping_server->IsStaticMember()) || (!thePrefs.GetDontRemoveStaticServers())) {
				theApp.emuledlg->serverwnd->serverlistctrl.RemoveServer(ping_server);
				return;
			}
			// [end] Mighty Knife
			theApp.emuledlg->serverwnd->serverlistctrl.RemoveServer(ping_server);
			return;
		}

		Packet* packet = new Packet(OP_GLOBSERVSTATREQ, 4);
		srand(tNow);
		uint32 uChallenge = 0x55AA0000 + GetRandomUInt16();
		ping_server->SetChallenge(uChallenge);
		PokeUInt32(packet->pBuffer, uChallenge);
		ping_server->SetLastPinged(GetTickCount());
		ping_server->SetLastPingedTime(tNow);
		ping_server->AddFailedCount();
		theApp.emuledlg->serverwnd->serverlistctrl.RefreshServer(ping_server);
		if (thePrefs.GetDebugServerUDPLevel() > 0)
			Debug(_T(">>> Sending OP__GlobServStatReq to server %s:%u\n"), ping_server->GetAddress(), ping_server->GetPort());
		theStats.AddUpDataOverheadServer(packet->size);
		theApp.serverconnect->SendUDPPacket(packet, ping_server, true);

		ping_server->SetLastDescPingedCount(false);
		if (ping_server->GetLastDescPingedCount() < 2)
		{
			// eserver 16.45+ supports a new OP_SERVER_DESC_RES answer, if the OP_SERVER_DESC_REQ contains a uint32
			// challenge, the server returns additional info with OP_SERVER_DESC_RES. To properly distinguish the
			// old and new OP_SERVER_DESC_RES answer, the challenge has to be selected carefully. The first 2 bytes 
			// of the challenge (in network byte order) MUST NOT be a valid string-len-int16!
			packet = new Packet(OP_SERVER_DESC_REQ, 4);
			uint32 uDescReqChallenge = ((uint32)GetRandomUInt16() << 16) + INV_SERV_DESC_LEN; // 0xF0FF = an 'invalid' string length.
			ping_server->SetDescReqChallenge(uDescReqChallenge);
			PokeUInt32(packet->pBuffer, uDescReqChallenge);
			theStats.AddUpDataOverheadServer(packet->size);
			if (thePrefs.GetDebugServerUDPLevel() > 0)
				Debug(_T(">>> Sending OP__ServDescReq     to server %s:%u, challenge %08x\n"), ping_server->GetAddress(), ping_server->GetPort(), uDescReqChallenge);
			theApp.serverconnect->SendUDPPacket(packet, ping_server, true);
		}
		else
		{
			ping_server->SetLastDescPingedCount(true);
		}
	}
}