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; }
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); } }
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; }
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; } }
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 } }
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); } }
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 } }
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); } } }