void CUPnPImplMiniLib::DeletePorts(bool bSkipLock){ // this function itself blocking, because its called at the end of eMule and we need to wait for it to finish // before going on anyway. It might be caled from the non-blocking StartDiscovery() function too however CSingleLock lockTest(&m_mutBusy); if (bSkipLock || lockTest.Lock(0)){ if (m_nOldTCPPort != 0){ if (m_pURLs == NULL || m_pURLs->controlURL == NULL || m_pIGDData == NULL){ ASSERT( false ); return; } const char achTCP[] = "TCP"; char achPort[10]; sprintf(achPort, "%u", m_nOldTCPPort); int nResult = UPNP_DeletePortMapping(m_pURLs->controlURL, m_pIGDData->servicetype, achPort, achTCP, NULL); if (nResult == UPNPCOMMAND_SUCCESS){ DebugLog(_T("Sucessfully removed mapping for port %u (%s)"), m_nOldTCPPort, _T("TCP")); m_nOldTCPPort = 0; } else DebugLogWarning(_T("Failed to remove mapping for port %u (%s)"), m_nOldTCPPort, _T("TCP")); } else{ DebugLog(_T("No UPnP Mappings to remove, aborting")); return; // UDP port cannot be set if TCP port was empty } if (m_nOldUDPPort != 0){ const char achTCP[] = "UDP"; char achPort[10]; sprintf(achPort, "%u", m_nOldUDPPort); int nResult = UPNP_DeletePortMapping(m_pURLs->controlURL, m_pIGDData->servicetype, achPort, achTCP, NULL); if (nResult == UPNPCOMMAND_SUCCESS){ DebugLog(_T("Sucessfully removed mapping for port %u (%s)"), m_nOldUDPPort, _T("UDP")); m_nOldTCPPort = 0; } else DebugLogWarning(_T("Failed to remove mapping for port %u (%s)"), m_nOldUDPPort, _T("UDP")); } if (m_nOldTCPWebPort != 0){ const char achTCP[] = "TCP"; char achPort[10]; sprintf(achPort, "%u", m_nOldTCPWebPort); int nResult = UPNP_DeletePortMapping(m_pURLs->controlURL, m_pIGDData->servicetype, achPort, achTCP, 0); if (nResult == UPNPCOMMAND_SUCCESS){ DebugLog(_T("Sucessfully removed mapping for webinterface port %u (%s)"), m_nOldTCPPort, _T("TCP")); m_nOldTCPWebPort = 0; } else DebugLogWarning(_T("Failed to remove mapping for webinterface port %u (%s)"), m_nOldTCPPort, _T("TCP")); } } else DebugLogError(_T("Unable to remove port mappings - implementation still busy")); }
void CClientList::RequestBuddy(Kademlia::CContact* contact, uint8 byConnectOptions) { uint32 nContactIP = ntohl(contact->GetIPAddress()); // don't connect ourself if (theApp.serverconnect->GetLocalIP() == nContactIP && thePrefs.GetPort() == contact->GetTCPPort()) return; CUpDownClient* pNewClient = FindClientByIP(nContactIP, contact->GetTCPPort()); if (!pNewClient) pNewClient = new CUpDownClient(0, contact->GetTCPPort(), contact->GetIPAddress(), 0, 0, false ); else if (pNewClient->GetKadState() != KS_NONE) return; // already busy with this client in some way (probably fw stuff), don't mess with it else if (IsKadFirewallCheckIP(nContactIP)){ // doing a kad firewall check with this IP, abort DEBUG_ONLY( DebugLogWarning(_T("KAD tcp Firewallcheck / Buddy request collosion for IP %s"), ipstr(nContactIP)) ); return; } //Add client to the lists to be processed. pNewClient->SetKadPort(contact->GetUDPPort()); pNewClient->SetKadState(KS_QUEUED_BUDDY); byte ID[16]; contact->GetClientID().ToByteArray(ID); pNewClient->SetUserHash(ID); pNewClient->SetConnectOptions(byConnectOptions, true, false); AddToKadList(pNewClient); //This method checks if this is a dup already. AddClient(pNewClient); }
bool CClientList::IncomingBuddy(Kademlia::CContact* contact, Kademlia::CUInt128* buddyID ) { uint32 nContactIP = ntohl(contact->GetIPAddress()); //If eMule already knows this client, abort this.. It could cause conflicts. //Although the odds of this happening is very small, it could still happen. if (FindClientByIP(nContactIP, contact->GetTCPPort())) return false; else if (IsKadFirewallCheckIP(nContactIP)){ // doing a kad firewall check with this IP, abort DEBUG_ONLY( DebugLogWarning(_T("KAD tcp Firewallcheck / Buddy request collosion for IP %s"), ipstr(nContactIP)) ); return false; } else if (theApp.serverconnect->GetLocalIP() == nContactIP && thePrefs.GetPort() == contact->GetTCPPort()) return false; // don't connect ourself //Add client to the lists to be processed. CUpDownClient* pNewClient = new CUpDownClient(0, contact->GetTCPPort(), contact->GetIPAddress(), 0, 0, false ); pNewClient->SetKadPort(contact->GetUDPPort()); pNewClient->SetKadState(KS_INCOMING_BUDDY); byte ID[16]; contact->GetClientID().ToByteArray(ID); pNewClient->SetUserHash(ID); //?? buddyID->ToByteArray(ID); pNewClient->SetBuddyID(ID); //MORPH START - Changed by SiRoB, Optimization /* AddToKadList(pNewClient); AddClient(pNewClient); */ m_KadList.AddTail(pNewClient); AddClient(pNewClient, true); //MORPH END - Changed by SiRoB, Optimization return true; }
CImplMswSocketTCP::CImplMswSocketTCP( CSocketTCP& publicSocket, Bool isBlocking ) : CImplStubSocketTCP( publicSocket, isBlocking ) { m_Socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( m_Socket == INVALID_SOCKET ) { DebugLogWarning( "CImplMswSocketTCP::CImplMswSocketTCP - Failed to create socket"); } if( isBlocking ) { DWORD nonBlocking = 1; if ( ioctlsocket( m_Socket, FIONBIO, &nonBlocking ) != 0 ) { DebugLogWarning( "CImplMswSocketTCP::CImplMswSocketTCP - Failed to set in blocking mode"); return; } } }
int CEncryptedDatagramSocket::DecryptReceivedServer(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwBaseKey, uint32 dbgIP) const{ 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 uchar achKeyData[7]; memcpy(achKeyData, &dwBaseKey, 4); achKeyData[4] = MAGICVALUE_UDP_SERVERCLIENT; memcpy(achKeyData + 5, pbyBufIn + 1, 2); // random key part sent from remote server MD5Sum md5(achKeyData, sizeof(achKeyData)); RC4_Key_Struct keyReceiveKey; RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); uint32 dwValue; RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); if (dwValue == MAGICVALUE_UDP_SYNC_SERVER){ // yup this is an encrypted packet if (thePrefs.GetDebugServerUDPLevel() > 0) DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from ServerIP: %s"), ipstr(dbgIP)) ); uint8 byPadLen; RC4Crypt(pbyBufIn + 7, (uchar*)&byPadLen, 1, &keyReceiveKey); 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) RC4Crypt(NULL, NULL, byPadLen, &keyReceiveKey); nResult -= byPadLen; *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 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 } }
int CEncryptedDatagramSocket::DecryptReceivedClient(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwIP) const{ int nResult = nBufLen; *ppbyBufOut = pbyBufIn; 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 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 MD5Sum md5(achKeyData, sizeof(achKeyData)); RC4_Key_Struct keyReceiveKey; RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); uint32 dwValue; RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); if (dwValue == MAGICVALUE_UDP_SYNC_CLIENT){ // yup this is an encrypted packet DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s"), 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; *ppbyBufOut = pbyBufIn + (nBufLen - nResult); RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey); theStats.AddDownDataOverheadCrypt(nBufLen - nResult); return nResult; // done } else{ DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }
bool CUPnPImplMiniLib::CStartDiscoveryThread::OpenPort(uint16 nPort, bool bTCP, char* pachLANIP){ const char achTCP[] = "TCP"; const char achUDP[] = "UDP"; const char achDescTCP[] = "eMule_TCP"; const char achDescUDP[] = "eMule_UDP"; char achPort[10]; sprintf(achPort, "%u", nPort); if (m_pOwner->m_bAbortDiscovery) return false; int nResult; if (bTCP) nResult = UPNP_AddPortMapping(m_pOwner->m_pURLs->controlURL, m_pOwner->m_pIGDData->servicetype , achPort, achPort, pachLANIP, achDescTCP, achTCP); else nResult = UPNP_AddPortMapping(m_pOwner->m_pURLs->controlURL, m_pOwner->m_pIGDData->servicetype , achPort, achPort, pachLANIP, achDescUDP, achUDP); if (nResult != UPNPCOMMAND_SUCCESS){ DebugLog(_T("Adding PortMapping failed, Error Code %u"), nResult); return false; } if (m_pOwner->m_bAbortDiscovery) return false; // make sure it really worked char achOutIP[20]; achOutIP[0] = 0; if (bTCP) nResult = UPNP_GetSpecificPortMappingEntry(m_pOwner->m_pURLs->controlURL, m_pOwner->m_pIGDData->servicetype , achPort, achTCP, achOutIP, achPort); else nResult = UPNP_GetSpecificPortMappingEntry(m_pOwner->m_pURLs->controlURL, m_pOwner->m_pIGDData->servicetype , achPort, achUDP, achOutIP, achPort); if (nResult == UPNPCOMMAND_SUCCESS && achOutIP[0] != 0){ DebugLog(_T("Sucessfully added mapping for port %u (%s) on local IP %S"), nPort, bTCP ? _T("TCP") : _T("UDP"), achOutIP); return true; } else { DebugLogWarning(_T("Failed to verfiy mapping for port %u (%s) on local IP %S - considering as failed"), nPort, bTCP ? _T("TCP") : _T("UDP"), achOutIP); // maybe counting this as error is a bit harsh as this may lead to false negatives, however if we would risk false postives // this would mean that the fallback implementations are not tried because eMule thinks it worked out fine return false; } }
Bool CImplMswSocketTCP::Bind( UInt16 port ) { sockaddr_in address ; address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_ANY); address.sin_port = htons(port); if( bind( m_Socket, (struct sockaddr*)&address, sizeof(sockaddr_in) ) == SOCKET_ERROR ) { DebugLogWarning( "CImplMswSocketTCP::Bind - Failed to bind socket"); return FALSE; } return TRUE; }
void CServerSocket::ProcessPacketError(UINT size, UINT opcode, LPCTSTR pszError) { if (thePrefs.GetVerbose()) { CString strServer; try{ if (cur_server) strServer.Format(_T("%s:%u"), cur_server->GetAddress(), cur_server->GetPort()); else strServer = _T("Unknown"); } catch(...){ } DebugLogWarning(false, _T("Error: Failed to process server TCP packet from %s: opcode=0x%02x size=%u - %s"), strServer, opcode, size, pszError); } }
bool CServerSocket::PacketReceived(Packet* packet) { #ifndef _DEBUG try { #endif theStats.AddDownDataOverheadServer(packet->size); if (packet->prot == OP_PACKEDPROT) { uint32 uComprSize = packet->size; if (!packet->UnPackPacket(250000)){ if (thePrefs.GetVerbose()) DebugLogError(_T("Failed to decompress server TCP packet: protocol=0x%02x opcode=0x%02x size=%u"), packet ? packet->prot : 0, packet ? packet->opcode : 0, packet ? packet->size : 0); return true; } packet->prot = OP_EDONKEYPROT; if (thePrefs.GetDebugServerTCPLevel() > 1) Debug(_T("Received compressed server TCP packet; opcode=0x%02x size=%u uncompr size=%u\n"), packet->opcode, uComprSize, packet->size); } if (packet->prot == OP_EDONKEYPROT) { ProcessPacket((const BYTE*)packet->pBuffer, packet->size, packet->opcode); } else { if (thePrefs.GetVerbose()) DebugLogWarning(_T("Received server TCP packet with unknown protocol: protocol=0x%02x opcode=0x%02x size=%u"), packet ? packet->prot : 0, packet ? packet->opcode : 0, packet ? packet->size : 0); } #ifndef _DEBUG } catch(...) { if (thePrefs.GetVerbose()) DebugLogError(_T("Error: Unhandled exception while processing server TCP packet: protocol=0x%02x opcode=0x%02x size=%u"), packet ? packet->prot : 0, packet ? packet->opcode : 0, packet ? packet->size : 0); ASSERT(0); return false; } #endif return true; }
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 } }
int CEncryptedDatagramSocket::DecryptReceivedClient(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwIP, uint16* nReceiverVerifyKey, uint16* nSenderVerifyKey) const{ int nResult = nBufLen; *ppbyBufOut = pbyBufIn; if (nResult <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/) return nResult; if (nReceiverVerifyKey == NULL || nSenderVerifyKey == NULL){ ASSERT( false ); 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) } bool bKad = (pbyBufIn[0] & 0x01) == 0; // check the marker bit if this is a kad or ed2k packet, this is only an indicator since old clients have it set random // might be an encrypted packet, try to decrypt RC4_Key_Struct keyReceiveKey; uint32 dwValue = 0; bool bFlipTry = false; do{ bKad = bFlipTry ? !bKad : bKad; MD5Sum md5; if (bKad){ 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{ 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)); } RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); bFlipTry = !bFlipTry; // next round try the other possibility } while (dwValue != MAGICVALUE_UDP_SYNC_CLIENT && bFlipTry); // try to decrypt as ed2k as well as kad packet if needed (max 2 rounds) if (dwValue == MAGICVALUE_UDP_SYNC_CLIENT){ // yup this is an encrypted packet DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s"), 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 <= 4){ 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 *nReceiverVerifyKey = PeekUInt16(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen); *nSenderVerifyKey = PeekUInt16(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 2); nResult -= 4; } else{ *nReceiverVerifyKey = 0; *nSenderVerifyKey = 0; } *ppbyBufOut = pbyBufIn + (nBufLen - nResult); RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey); theStats.AddDownDataOverheadCrypt(nBufLen - nResult); return nResult; // done } else{ DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }
int CEncryptedStreamSocket::Receive(void* lpBuf, int nBufLen, int nFlags){ m_nObfuscationBytesReceived = CAsyncSocketEx::Receive(lpBuf, nBufLen, nFlags); m_bFullReceive = m_nObfuscationBytesReceived == (uint32_t)nBufLen; if(m_nObfuscationBytesReceived == SOCKET_ERROR || m_nObfuscationBytesReceived <= 0){ return m_nObfuscationBytesReceived; } switch (m_StreamCryptState) { case ECS_NONE: // disabled, just pass it through return m_nObfuscationBytesReceived; case ECS_PENDING: case ECS_PENDING_SERVER: ASSERT( false ); DebugLogError(_T("CEncryptedStreamSocket Received data before sending on outgoing connection")); m_StreamCryptState = ECS_NONE; return m_nObfuscationBytesReceived; case ECS_UNKNOWN:{ uint32_t nRead = 1; bool bNormalHeader = false; switch (((uchar*)lpBuf)[0]){ case OP_EDONKEYPROT: case OP_PACKEDPROT: case OP_EMULEPROT: bNormalHeader = true; break; } if (!bNormalHeader){ StartNegotiation(false); const uint32_t nNegRes = Negotiate((uchar*)lpBuf + nRead, m_nObfuscationBytesReceived - nRead); if (nNegRes == (-1)) return 0; nRead += nNegRes; if (nRead != (uint32_t)m_nObfuscationBytesReceived){ // this means we have more data then the current negotiation step required (or there is a bug) and this should never happen // (note: even if it just finished the handshake here, there still can be no data left, since the other client didnt received our response yet) DebugLogError(_T("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (1)"), DbgGetIPString()); OnError(ERR_ENCRYPTION); } return 0; } else{ // doesn't seems to be encrypted m_StreamCryptState = ECS_NONE; // if we require an encrypted connection, cut the connection here. This shouldn't happen that often // at least with other up-to-date eMule clients because they check for incompability before connecting if possible if (thePrefs.IsClientCryptLayerRequired()){ // TODO: Remove me when i have been solved // Even if the Require option is enabled, we currently have to accept unencrypted connection which are made // for lowid/firewall checks from servers and other from us selected client. Otherwise, this option would // always result in a lowid/firewalled status. This is of course not nice, but we can't avoid this walkarround // untill servers and kad completely support encryption too, which will at least for kad take a bit // only exception is the .ini option ClientCryptLayerRequiredStrict which will even ignore test connections // Update: New server now support encrypted callbacks SOCKADDR_IN sockAddr = {0}; int nSockAddrLen = sizeof(sockAddr); GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (thePrefs.IsClientCryptLayerRequiredStrict() || (!theApp.serverconnect->AwaitingTestFromIP(sockAddr.sin_addr.S_un.S_addr) && !theApp.clientlist->IsKadFirewallCheckIP(sockAddr.sin_addr.S_un.S_addr)) ) { #if defined(_DEBUG) || defined(_BETA) // TODO: Remove after testing AddDebugLogLine(DLP_DEFAULT, false, _T("Rejected incoming connection because Obfuscation was required but not used %s"), DbgGetIPString() ); #endif OnError(ERR_ENCRYPTION_NOTALLOWED); return 0; } else AddDebugLogLine(DLP_DEFAULT, false, _T("Incoming unencrypted firewallcheck connection permitted despite RequireEncryption setting - %s"), DbgGetIPString() ); } return m_nObfuscationBytesReceived; // buffer was unchanged, we can just pass it through } } case ECS_ENCRYPTING: // basic obfuscation enabled and set, so decrypt and pass along RC4Crypt((uchar*)lpBuf, (uchar*)lpBuf, m_nObfuscationBytesReceived, m_pRC4ReceiveKey); return m_nObfuscationBytesReceived; case ECS_NEGOTIATING:{ const uint32_t nRead = Negotiate((uchar*)lpBuf, m_nObfuscationBytesReceived); if (nRead == (-1)) return 0; else if (nRead != (uint32_t)m_nObfuscationBytesReceived && m_StreamCryptState != ECS_ENCRYPTING){ // this means we have more data then the current negotiation step required (or there is a bug) and this should never happen DebugLogError(_T("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (2)"), DbgGetIPString()); OnError(ERR_ENCRYPTION); return 0; } else if (nRead != (uint32_t)m_nObfuscationBytesReceived && m_StreamCryptState == ECS_ENCRYPTING){ // we finished the handshake and if we this was an outgoing connection it is allowed (but strange and unlikely) that the client sent payload DebugLogWarning(_T("CEncryptedStreamSocket: Client %s has finished the handshake but also sent payload on a outgoing connection"), DbgGetIPString()); memmove(lpBuf, (uchar*)lpBuf + nRead, m_nObfuscationBytesReceived - nRead); return m_nObfuscationBytesReceived - nRead; } else return 0; } default: ASSERT( false ); return m_nObfuscationBytesReceived; } }
void CClientUDPSocket::OnReceive(int nErrorCode) { if (nErrorCode) { if (thePrefs.GetVerbose()) DebugLogError(_T("Error: Client UDP socket, error on receive event: %s"), GetErrorMessage(nErrorCode, 1)); } BYTE buffer[5000]; SOCKADDR_IN sockAddr = {0}; int iSockAddrLen = sizeof sockAddr; int length = ReceiveFrom(buffer, sizeof buffer, (SOCKADDR*)&sockAddr, &iSockAddrLen); if (length >= 1 && !(theApp.ipfilter->IsFiltered(sockAddr.sin_addr.S_un.S_addr) || theApp.clientlist->IsBannedClient(sockAddr.sin_addr.S_un.S_addr))) { CString strError; try { switch (buffer[0]) { case OP_EMULEPROT: { if (length >= 2) ProcessPacket(buffer+2, length-2, buffer[1], sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port)); else throw CString(_T("eMule packet too short")); break; } case OP_KADEMLIAPACKEDPROT: { theStats.AddDownDataOverheadKad(length); if (length >= 2) { uint32 nNewSize = length*10+300; byte* unpack = new byte[nNewSize]; uLongf unpackedsize = nNewSize-2; int iZLibResult = uncompress(unpack+2, &unpackedsize, buffer+2, length-2); if (iZLibResult == Z_OK) { unpack[0] = OP_KADEMLIAHEADER; unpack[1] = buffer[1]; try { Kademlia::CKademlia::processPacket(unpack, unpackedsize+2, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port)); } catch(...) { delete[] unpack; throw; } } else { delete[] unpack; CString strError; strError.Format(_T("Failed to uncompress Kad packet: zip error: %d (%hs)"), iZLibResult, zError(iZLibResult)); throw strError; } delete[] unpack; } else throw CString(_T("Kad packet (compressed) too short")); break; } case OP_KADEMLIAHEADER: { theStats.AddDownDataOverheadKad(length); if (length >= 2) Kademlia::CKademlia::processPacket(buffer, length, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port)); else throw CString(_T("Kad packet too short")); break; } default: { CString strError; strError.Format(_T("Unknown protocol 0x%02x"), buffer[0]); throw strError; } } } catch(CFileException* error) { error->Delete(); strError = _T("Invalid packet received"); } catch(CMemoryException* error) { error->Delete(); strError = _T("Memory exception"); } catch(CString error) { strError = error; } catch(Kademlia::CIOException* error) { error->Delete(); strError = _T("Invalid packet received"); } catch(CException* error) { error->Delete(); strError = _T("General packet error"); } catch(...) { strError = _T("Unknown exception"); ASSERT(0); } if (thePrefs.GetVerbose() && !strError.IsEmpty()) { CString strClientInfo; CUpDownClient* client; if (buffer[0] == OP_EMULEPROT) client = theApp.clientlist->FindClientByIP_UDP(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port)); else client = theApp.clientlist->FindClientByIP_KadPort(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port)); if (client) strClientInfo = client->DbgGetClientInfo(); else strClientInfo.Format(_T("%s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port)); DebugLogWarning(_T("Client UDP socket: prot=0x%02x opcode=0x%02x size=%u %s: %s"), buffer[0], buffer[1], length, strError, strClientInfo); } } else if (length == SOCKET_ERROR) { DWORD dwError = WSAGetLastError(); if (dwError == WSAECONNRESET) { // Depending on local and remote OS and depending on used local (remote?) router we may receive // WSAECONNRESET errors. According some KB articles, this is a special way of winsock to report // that a sent UDP packet was not received by the remote host because it was not listening on // the specified port -> no eMule running there. // // TODO: So, actually we should do something with this information and drop the related Kad node // or eMule client... ; } if (thePrefs.GetVerbose() && dwError != WSAECONNRESET) { CString strClientInfo; if (iSockAddrLen > 0 && sockAddr.sin_addr.S_un.S_addr != 0 && sockAddr.sin_addr.S_un.S_addr != INADDR_NONE) strClientInfo.Format(_T(" from %s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port)); DebugLogError(_T("Error: Client UDP socket, failed to receive data%s: %s"), strClientInfo, GetErrorMessage(dwError, 1)); } } }
int CUPnPImplMiniLib::CStartDiscoveryThread::Run() { DbgSetThreadName("CUPnPImplMiniLib::CStartDiscoveryThread"); if ( !m_pOwner ) return 0; CSingleLock sLock(&m_pOwner->m_mutBusy); if (!sLock.Lock(0)){ DebugLogWarning(_T("CUPnPImplMiniLib::CStartDiscoveryThread::Run, failed to acquire Lock, another Mapping try might be running already")); return 0; } if (m_pOwner->m_bAbortDiscovery) // requesting to abort ASAP? return 0; UPNPDev* structDeviceList = upnpDiscover(2000, NULL, NULL); if (structDeviceList == NULL){ DebugLog(_T("UPNP: No Internet Gateway Devices found, aborting")); m_pOwner->m_bUPnPPortsForwarded = TRIS_FALSE; m_pOwner->SendResultMessage(); return 0; } if (m_pOwner->m_bAbortDiscovery){ // requesting to abort ASAP? freeUPNPDevlist(structDeviceList); return 0; } DebugLog(_T("List of UPNP devices found on the network:")); for(UPNPDev* pDevice = structDeviceList; pDevice != NULL; pDevice = pDevice->pNext) { DebugLog(_T("Desc: %S, st: %S"), pDevice->descURL, pDevice->st); } m_pOwner->m_pURLs = new UPNPUrls; ZeroMemory(m_pOwner->m_pURLs, sizeof(UPNPUrls)); m_pOwner->m_pIGDData = new IGDdatas; ZeroMemory(m_pOwner->m_pIGDData, sizeof(IGDdatas)); char achLanIP[16]; achLanIP[0] = 0; int iResult = UPNP_GetValidIGD(structDeviceList, m_pOwner->m_pURLs, m_pOwner->m_pIGDData, achLanIP, sizeof(achLanIP)); switch (iResult){ case 1: DebugLog(_T("Found valid IGD : %S"), m_pOwner->m_pURLs->controlURL); break; case 2: DebugLog(_T("Found a (not connected?) IGD : %S - Trying to continue anyway"), m_pOwner->m_pURLs->controlURL); break; case 3: DebugLog(_T("UPnP device found. Is it an IGD ? : %S - Trying to continue anyway"), m_pOwner->m_pURLs->controlURL); break; default: DebugLog(_T("Found device (igd ?) : %S - Trying to continue anyway"), m_pOwner->m_pURLs->controlURL); } freeUPNPDevlist(structDeviceList); DebugLog(_T("Our LAN IP: %S"), achLanIP); if (m_pOwner->m_bAbortDiscovery) // requesting to abort ASAP? return 0; // do we still have old mappings? Remove them first m_pOwner->DeletePorts(true); bool bSucceeded = OpenPort(m_pOwner->m_nTCPPort, true, achLanIP); if (bSucceeded && m_pOwner->m_nUDPPort != 0) bSucceeded = OpenPort(m_pOwner->m_nUDPPort, false, achLanIP); if (!m_pOwner->m_bAbortDiscovery){ // dont send a result on a abort request m_pOwner->m_bUPnPPortsForwarded = bSucceeded ? TRIS_TRUE : TRIS_FALSE; m_pOwner->SendResultMessage(); } return 0; }
int CUPnPImplMiniLib::CStartDiscoveryThread::Run() { DbgSetThreadName("CUPnPImplMiniLib::CStartDiscoveryThread"); if ( !m_pOwner ) return 0; CSingleLock sLock(&m_pOwner->m_mutBusy); if (!sLock.Lock(0)){ DebugLogWarning(_T("CUPnPImplMiniLib::CStartDiscoveryThread::Run, failed to acquire Lock, another Mapping try might be running already")); return 0; } if (m_pOwner->m_bAbortDiscovery) // requesting to abort ASAP? return 0; bool bSucceeded = false; #if !(defined(_DEBUG) || defined(_BETA)) try #endif { if (!m_pOwner->m_bCheckAndRefresh) { UPNPDev* structDeviceList = upnpDiscover(2000, NULL, NULL, NULL); if (structDeviceList == NULL){ DebugLog(_T("UPNP: No Internet Gateway Devices found, aborting")); m_pOwner->m_bUPnPPortsForwarded = TRIS_FALSE; m_pOwner->SendResultMessage(); return 0; } if (m_pOwner->m_bAbortDiscovery){ // requesting to abort ASAP? freeUPNPDevlist(structDeviceList); return 0; } DebugLog(_T("List of UPNP devices found on the network:")); for(UPNPDev* pDevice = structDeviceList; pDevice != NULL; pDevice = pDevice->pNext) { DebugLog(_T("Desc: %S, st: %S"), pDevice->descURL, pDevice->st); } m_pOwner->m_pURLs = new UPNPUrls; ZeroMemory(m_pOwner->m_pURLs, sizeof(UPNPUrls)); m_pOwner->m_pIGDData = new IGDdatas; ZeroMemory(m_pOwner->m_pIGDData, sizeof(IGDdatas)); m_pOwner->m_achLanIP[0] = 0; int iResult = UPNP_GetValidIGD(structDeviceList, m_pOwner->m_pURLs, m_pOwner->m_pIGDData, m_pOwner->m_achLanIP, sizeof(m_pOwner->m_achLanIP)); freeUPNPDevlist(structDeviceList); bool bNotFound = false; switch (iResult){ case 1: DebugLog(_T("Found valid IGD : %S"), m_pOwner->m_pURLs->controlURL); break; case 2: DebugLog(_T("Found a (not connected?) IGD : %S - Trying to continue anyway"), m_pOwner->m_pURLs->controlURL); break; case 3: DebugLog(_T("UPnP device found. Is it an IGD ? : %S - Trying to continue anyway"), m_pOwner->m_pURLs->controlURL); break; default: DebugLog(_T("Found device (igd ?) : %S - Aborting"), m_pOwner->m_pURLs->controlURL != NULL ? m_pOwner->m_pURLs->controlURL : "(none)"); bNotFound = true; } if (bNotFound || m_pOwner->m_pURLs->controlURL == NULL) { m_pOwner->m_bUPnPPortsForwarded = TRIS_FALSE; m_pOwner->SendResultMessage(); return 0; } DebugLog(_T("Our LAN IP: %S"), m_pOwner->m_achLanIP); if (m_pOwner->m_bAbortDiscovery) // requesting to abort ASAP? return 0; // do we still have old mappings? Remove them first m_pOwner->DeletePorts(true); } bSucceeded = OpenPort(m_pOwner->m_nTCPPort, true, m_pOwner->m_achLanIP, m_pOwner->m_bCheckAndRefresh); if (bSucceeded && m_pOwner->m_nUDPPort != 0) bSucceeded = OpenPort(m_pOwner->m_nUDPPort, false, m_pOwner->m_achLanIP, m_pOwner->m_bCheckAndRefresh); if (bSucceeded && m_pOwner->m_nTCPWebPort != 0) OpenPort(m_pOwner->m_nTCPWebPort, true, m_pOwner->m_achLanIP, m_pOwner->m_bCheckAndRefresh); // don't fail if only the webinterface port fails for some reason } #if !(defined(_DEBUG) || defined(_BETA)) catch(...) { DebugLogError(_T("Unknown Exception in CUPnPImplMiniLib::CStartDiscoveryThread::Run()")); } #endif if (!m_pOwner->m_bAbortDiscovery){ // dont send a result on a abort request m_pOwner->m_bUPnPPortsForwarded = bSucceeded ? TRIS_TRUE : TRIS_FALSE; m_pOwner->m_bSucceededOnce |= bSucceeded; m_pOwner->SendResultMessage(); } return 0; }
void CListenSocket::OnAccept(int nErrorCode) { if (!nErrorCode) { m_nPendingConnections++; if (m_nPendingConnections < 1){ ASSERT(0); m_nPendingConnections = 1; } if (TooManySockets(true) && !CGlobalVariable::serverconnect->IsConnecting()){ StopListening(); return; } else if (!bListening) ReStartListening(); //If the client is still at maxconnections, this will allow it to go above it.. But if you don't, you will get a lowID on all servers. uint32 nFataErrors = 0; while (m_nPendingConnections > 0) { m_nPendingConnections--; CClientReqSocket* newclient; SOCKADDR_IN SockAddr = {0}; int iSockAddrLen = sizeof SockAddr; if (thePrefs.GetConditionalTCPAccept() && !thePrefs.GetProxySettings().UseProxy) { _iAcceptConnectionCondRejected = 0; SOCKET sNew = WSAAccept(m_SocketData.hSocket, (SOCKADDR*)&SockAddr, &iSockAddrLen, AcceptConnectionCond, 0); if (sNew == INVALID_SOCKET){ DWORD nError = GetLastError(); if (nError == WSAEWOULDBLOCK){ DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections); m_nPendingConnections = 0; break; } else{ if (nError != WSAECONNREFUSED || _iAcceptConnectionCondRejected == 0){ DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1)); nFataErrors++; } else if (_iAcceptConnectionCondRejected == 1) theStats.filteredclients++; } if (nFataErrors > 10){ // the question is what todo on a error. We cant just ignore it because then the backlog will fill up // and lock everything. We can also just endlos try to repeat it because this will lock up eMule // this should basically never happen anyway // however if we are in such a position, try to reinitalize the socket. DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__); Close(); StartListening(); m_nPendingConnections = 0; break; } continue; } newclient = new CClientReqSocket; VERIFY( newclient->InitAsyncSocketExInstance() ); newclient->m_SocketData.hSocket = sNew; newclient->AttachHandle(sNew); AddConnection(); } else { newclient = new CClientReqSocket; if (!Accept(*newclient, (SOCKADDR*)&SockAddr, &iSockAddrLen)){ newclient->Safe_Delete(); DWORD nError = GetLastError(); if (nError == WSAEWOULDBLOCK){ DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections); m_nPendingConnections = 0; break; } else{ DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1)); nFataErrors++; } if (nFataErrors > 10){ // the question is what todo on a error. We cant just ignore it because then the backlog will fill up // and lock everything. We can also just endlos try to repeat it because this will lock up eMule // this should basically never happen anyway // however if we are in such a position, try to reinitalize the socket. DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__); Close(); StartListening(); m_nPendingConnections = 0; break; } continue; } AddConnection(); if (SockAddr.sin_addr.S_un.S_addr == 0) // for safety.. { iSockAddrLen = sizeof SockAddr; newclient->GetPeerName((SOCKADDR*)&SockAddr, &iSockAddrLen); DebugLogWarning(_T("SockAddr.sin_addr.S_un.S_addr == 0; GetPeerName returned %s"), ipstr(SockAddr.sin_addr.S_un.S_addr)); } ASSERT( SockAddr.sin_addr.S_un.S_addr != 0 && SockAddr.sin_addr.S_un.S_addr != INADDR_NONE ); if (CGlobalVariable::ipfilter->IsFiltered(SockAddr.sin_addr.S_un.S_addr)){ if (thePrefs.GetLogFilteredIPs()) AddDebugLogLine(false, _T("Rejecting connection attempt (IP=%s) - IP filter (%s)"), ipstr(SockAddr.sin_addr.S_un.S_addr), CGlobalVariable::ipfilter->GetLastHit()); newclient->Safe_Delete(); theStats.filteredclients++; continue; } if (CGlobalVariable::clientlist->IsBannedClient(SockAddr.sin_addr.S_un.S_addr)){ if (thePrefs.GetLogBannedClients()){ CUpDownClient* pClient = CGlobalVariable::clientlist->FindClientByIP(SockAddr.sin_addr.S_un.S_addr); AddDebugLogLine(false, _T("Rejecting connection attempt of banned client %s %s"), ipstr(SockAddr.sin_addr.S_un.S_addr), pClient->DbgGetClientInfo()); } newclient->Safe_Delete(); continue; } } newclient->AsyncSelect(FD_WRITE | FD_READ | FD_CLOSE); } ASSERT( m_nPendingConnections >= 0 ); } }
int CAICHSyncThread::Run() { //MORPH START SLUGFILLER: SafeHash CReadWriteLock lock(&theApp.m_threadlock); if (!lock.ReadLock(0)) return 0; // MORPH END SLUGFILLER: SafeHash if ( !theApp.emuledlg->IsRunning() ) return 0; // we need to keep a lock on this file while the thread is running CSingleLock lockKnown2Met(&CAICHRecoveryHashSet::m_mutKnown2File); lockKnown2Met.Lock(); CSafeFile file; bool bJustCreated = ConvertToKnown2ToKnown264(&file); // we collect all masterhashs which we find in the known2.met and store them in a list CList<CAICHHash> liKnown2Hashs; CString fullpath = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR); fullpath.Append(KNOWN2_MET_FILENAME); CFileException fexp; uint32 nLastVerifiedPos = 0; if (!bJustCreated && !file.Open(fullpath,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyNone, &fexp)){ if (fexp.m_cause != CFileException::fileNotFound){ CString strError(_T("Failed to load ") KNOWN2_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; } try { if (file.GetLength() >= 1){ uint8 header = file.ReadUInt8(); if (header != KNOWN2_MET_VERSION){ AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName()); } //setvbuf(file.m_pStream, NULL, _IOFBF, 16384); uint32 nExistingSize = (UINT)file.GetLength(); uint32 nHashCount; while (file.GetPosition() < nExistingSize){ liKnown2Hashs.AddTail(CAICHHash(&file)); nHashCount = file.ReadUInt32(); if (file.GetPosition() + nHashCount*CAICHHash::GetHashSize() > nExistingSize){ AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName()); } // skip the rest of this hashset file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current); nLastVerifiedPos = (UINT)file.GetPosition(); } } else file.WriteUInt8(KNOWN2_MET_VERSION); } catch(CFileException* error){ if (error->m_cause == CFileException::endOfFile){ LogError(LOG_STATUSBAR,GetResString(IDS_ERR_MET_BAD), KNOWN2_MET_FILENAME); // truncate the file to the size to the last verified valid pos try{ file.SetLength(nLastVerifiedPos); if (file.GetLength() == 0){ file.SeekToBegin(); file.WriteUInt8(KNOWN2_MET_VERSION); } } catch(CFileException* error2){ error2->Delete(); } } else{ TCHAR buffer[MAX_CFEXP_ERRORMSG]; error->GetErrorMessage(buffer, ARRSIZE(buffer)); LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer); } error->Delete(); return false; } // now we check that all files which are in the sharedfilelist have a corresponding hash in out list // those who don'T are added to the hashinglist CList<CAICHHash> liUsedHashs; CSingleLock sharelock(&theApp.sharedfiles->m_mutWriteList); sharelock.Lock(); bool bDbgMsgCreatingPartHashs = true; for (int i = 0; i < theApp.sharedfiles->GetCount(); i++){ CKnownFile* pCurFile = theApp.sharedfiles->GetFileByIndex(i); if (pCurFile != NULL && !pCurFile->IsPartFile() ) { if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()) // in case of shutdown while still hashing return 0; if (pCurFile->GetFileIdentifier().HasAICHHash()){ bool bFound = false; for (POSITION pos = liKnown2Hashs.GetHeadPosition();pos != 0;) { CAICHHash current_hash = liKnown2Hashs.GetNext(pos); if (current_hash == pCurFile->GetFileIdentifier().GetAICHHash()){ bFound = true; liUsedHashs.AddTail(current_hash); pCurFile->SetAICHRecoverHashSetAvailable(true); // Has the file the proper AICH Parthashset? If not probably upgrading, create it if (!pCurFile->GetFileIdentifier().HasExpectedAICHHashCount()) { if (bDbgMsgCreatingPartHashs) { bDbgMsgCreatingPartHashs = false; DebugLogWarning(_T("Missing AICH Part Hashsets for known files - maybe upgrading from earlier version. Creating them out of full AICH Recovery Hashsets, shouldn't take too long")); } CAICHRecoveryHashSet tempHashSet(pCurFile, pCurFile->GetFileSize()); tempHashSet.SetMasterHash(pCurFile->GetFileIdentifier().GetAICHHash(), AICH_HASHSETCOMPLETE); if (!tempHashSet.LoadHashSet()) { ASSERT( false ); DebugLogError(_T("Failed to load full AICH Recovery Hashset - known2.met might be corrupt. Unable to create AICH Part Hashset - %s"), pCurFile->GetFileName()); } else { if (!pCurFile->GetFileIdentifier().SetAICHHashSet(tempHashSet)) { DebugLogError(_T("Failed to create AICH Part Hashset out of full AICH Recovery Hashset - %s"), pCurFile->GetFileName()); ASSERT( false ); } ASSERT(pCurFile->GetFileIdentifier().HasExpectedAICHHashCount()); } } //theApp.QueueDebugLogLine(false, _T("%s - %s"), current_hash.GetString(), pCurFile->GetFileName()); /*#ifdef _DEBUG // in debugmode we load and verify all hashsets CAICHRecoveryHashSet* pTempHashSet = new CAICHRecoveryHashSet(pCurFile); pTempHashSet->SetFileSize(pCurFile->GetFileSize()); pTempHashSet->SetMasterHash(pCurFile->GetFileIdentifier().GetAICHHash(), AICH_HASHSETCOMPLETE) ASSERT( pTempHashSet->LoadHashSet() ); delete pTempHashSet; #endif*/ break; } } if (bFound) // hashset is available, everything fine with this file continue; } pCurFile->SetAICHRecoverHashSetAvailable(false); m_liToHash.AddTail(pCurFile); } } sharelock.Unlock(); // removed all unused AICH hashsets from known2.met if (liUsedHashs.GetCount() != liKnown2Hashs.GetCount() && // EastShare START - Added by TAHO, .met file control /* (!thePrefs.IsRememberingDownloadedFiles() || thePrefs.DoPartiallyPurgeOldKnownFiles())) */ (!thePrefs.IsRememberingDownloadedFiles() || thePrefs.DoPartiallyPurgeOldKnownFiles() || thePrefs.DoCompletlyPurgeOldKnownFiles() || thePrefs.DoRemoveAichImmediatly() ) ) // EastShare END - Added by TAHO, .met file control { file.SeekToBegin(); try { uint8 header = file.ReadUInt8(); if (header != KNOWN2_MET_VERSION){ AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName()); } uint32 nExistingSize = (UINT)file.GetLength(); uint32 nHashCount; ULONGLONG posWritePos = file.GetPosition(); ULONGLONG posReadPos = file.GetPosition(); uint32 nPurgeCount = 0; uint32 nPurgeBecauseOld = 0; while (file.GetPosition() < nExistingSize){ CAICHHash aichHash(&file); nHashCount = file.ReadUInt32(); if (file.GetPosition() + nHashCount*CAICHHash::GetHashSize() > nExistingSize){ AfxThrowFileException(CFileException::endOfFile, 0, file.GetFileName()); } if (!thePrefs.IsRememberingDownloadedFiles() && liUsedHashs.Find(aichHash) == NULL) { // unused hashset skip the rest of this hashset file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current); nPurgeCount++; } else if (thePrefs.IsRememberingDownloadedFiles() && theApp.knownfiles->ShouldPurgeAICHHashset(aichHash)) { // EastShare START - Added by TAHO, .met file control /* ASSERT( thePrefs.DoPartiallyPurgeOldKnownFiles() ); */ ASSERT( thePrefs.DoPartiallyPurgeOldKnownFiles() || thePrefs.DoRemoveAichImmediatly()); // EastShare END - Added by TAHO, .met file control // also unused (purged) hashset skip the rest of this hashset file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current); nPurgeCount++; nPurgeBecauseOld++; } else if(nPurgeCount == 0){ // used Hashset, but it does not need to be moved as nothing changed yet file.Seek(nHashCount*CAICHHash::GetHashSize(), CFile::current); posWritePos = file.GetPosition(); CAICHRecoveryHashSet::AddStoredAICHHash(aichHash); } else{ // used Hashset, move position in file BYTE* buffer = new BYTE[nHashCount*CAICHHash::GetHashSize()]; file.Read(buffer, nHashCount*CAICHHash::GetHashSize()); posReadPos = file.GetPosition(); file.Seek(posWritePos, CFile::begin); file.Write(aichHash.GetRawHash(), CAICHHash::GetHashSize()); file.WriteUInt32(nHashCount); file.Write(buffer, nHashCount*CAICHHash::GetHashSize()); delete[] buffer; posWritePos = file.GetPosition(); file.Seek(posReadPos, CFile::begin); CAICHRecoveryHashSet::AddStoredAICHHash(aichHash); } } posReadPos = file.GetPosition(); file.SetLength(posWritePos); theApp.QueueDebugLogLine(false, _T("Cleaned up known2.met, removed %u hashsets and purged %u hashsets of old known files (%s)") , nPurgeCount - nPurgeBecauseOld, nPurgeBecauseOld, CastItoXBytes(posReadPos-posWritePos)); file.Flush(); file.Close(); } catch(CFileException* error){ if (error->m_cause == CFileException::endOfFile){ // we just parsed this files some ms ago, should never happen here ASSERT( false ); } else{ TCHAR buffer[MAX_CFEXP_ERRORMSG]; error->GetErrorMessage(buffer, ARRSIZE(buffer)); LogError(LOG_STATUSBAR,GetResString(IDS_ERR_SERVERMET_UNKNOWN),buffer); } error->Delete(); return false; } } else { // remember (/index) all hashs which are stored in the file for faster checking lateron for (POSITION pos = liKnown2Hashs.GetHeadPosition();pos != 0;) { CAICHRecoveryHashSet::AddStoredAICHHash(liKnown2Hashs.GetNext(pos)); } } lockKnown2Met.Unlock(); // warn the user if he just upgraded if (thePrefs.IsFirstStart() && !m_liToHash.IsEmpty() && !bJustCreated){ LogWarning(GetResString(IDS_AICH_WARNUSER)); } if (!m_liToHash.IsEmpty()){ theApp.QueueLogLine(true, GetResString(IDS_AICH_SYNCTOTAL), m_liToHash.GetCount() ); theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount()); // let first all normal hashing be done before starting out synchashing CSingleLock sLock1(&theApp.hashing_mut); // only one filehash at a time while (theApp.sharedfiles->GetHashingCount() != 0){ Sleep(100); if (!CemuleDlg::IsRunning()) return 0; } sLock1.Lock(); uint32 cDone = 0; for (POSITION pos = m_liToHash.GetHeadPosition();pos != 0; cDone++) { if (!CemuleDlg::IsRunning()){ // in case of shutdown while still hashing return 0; } theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(m_liToHash.GetCount()-cDone); if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL) theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount(); CKnownFile* pCurFile = m_liToHash.GetNext(pos); // just to be sure that the file hasnt been deleted lately if (!(theApp.knownfiles->IsKnownFile(pCurFile) && theApp.sharedfiles->GetFileByID(pCurFile->GetFileHash())) ) continue; theApp.QueueLogLine(false, GetResString(IDS_AICH_CALCFILE), pCurFile->GetFileName()); if(!pCurFile->CreateAICHHashSetOnly()) theApp.QueueDebugLogLine(false, _T("Failed to create AICH Hashset while sync. for file %s"), pCurFile->GetFileName()); } theApp.emuledlg->sharedfileswnd->sharedfilesctrl.SetAICHHashing(0); if (theApp.emuledlg->sharedfileswnd->sharedfilesctrl.m_hWnd != NULL) theApp.emuledlg->sharedfileswnd->sharedfilesctrl.ShowFilesCount(); sLock1.Unlock(); } theApp.QueueDebugLogLine(false, _T("AICHSyncThread finished")); return 0; }