Пример #1
0
        private void ProcessPacketError(uint size, uint opcode, uint nIP, ushort nUDPPort,
                                        Exception ex)
        {
            string     strName = string.Empty;
            ED2KServer pServer = MuleApplication.Instance.ServerList.GetServerByIPUDP(nIP, nUDPPort);

            if (pServer != null)
            {
                strName = " (" + pServer.ServerName + ")";
            }
            MpdUtilities.DebugLogWarning(false,
                                         string.Format("Error: Failed to process server UDP packet from {0}:{1}{2} opcode=0x{3} size={4} - {5}",
                                                       MpdUtilities.IP2String(nIP), nUDPPort, strName, opcode, size, ex.Message), ex);
        }
        public virtual int DecryptReceivedClient(byte[] pbyBufIn, int nBufLen,
                                                 out byte[] ppbyBufOut, uint dwIP, out uint nReceiverVerifyKey, out uint nSenderVerifyKey)
        {
            int nResult = nBufLen;

            ppbyBufOut         = pbyBufIn;
            nReceiverVerifyKey = 0;
            nSenderVerifyKey   = 0;

            if (nResult <= CRYPT_HEADER_WITHOUTPADDING /*|| !MuleApplication.Instance.Preference.IsClientCryptLayerSupported()*/)
            {
                return(nResult);
            }

            switch (pbyBufIn[0])
            {
            case MuleConstants.PROTOCOL_EMULEPROT:
            case MuleConstants.PROTOCOL_KADEMLIAPACKEDPROT:
            case MuleConstants.PROTOCOL_KADEMLIAHEADER:
            case MuleConstants.PROTOCOL_UDPRESERVEDPROT1:
            case MuleConstants.PROTOCOL_UDPRESERVEDPROT2:
            case MuleConstants.PROTOCOL_PACKEDPROT:
                return(nResult);    // no encrypted packet (see description on top)
            }

            // might be an encrypted packet, try to decrypt
            RC4Key keyReceiveKey = null;
            uint   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 = (byte)(((pbyBufIn[0] & 0x03) == 3) ? 1 : (pbyBufIn[0] & 0x03));
            byte byTries;

            if (MuleApplication.Instance.KadEngine.Preference == 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--;
                MD5    md5     = MD5.Create();
                byte[] rawHash = null;
                if (byCurrentTry == 0)
                {
                    // kad packet with NodeID as key
                    bKad            = true;
                    bKadRecvKeyUsed = false;
                    if (MuleApplication.Instance.KadEngine.Preference != null)
                    {
                        byte[] achKeyData = new byte[18];
                        Array.Copy(MuleApplication.Instance.KadEngine.Preference.KadID.Bytes, 0, achKeyData, 0, 16);
                        Array.Copy(pbyBufIn, 1, achKeyData, 16, 2); // random key part sent from remote client
                        rawHash = md5.ComputeHash(achKeyData);
                    }
                }
                else if (byCurrentTry == 1)
                {
                    // ed2k packet
                    bKad            = false;
                    bKadRecvKeyUsed = false;
                    byte[] achKeyData = new byte[23];
                    MpdUtilities.Md4Cpy(achKeyData, MuleApplication.Instance.Preference.UserHash);
                    achKeyData[20] = MAGICVALUE_UDP;
                    Array.Copy(BitConverter.GetBytes(dwIP), 0, achKeyData, 16, 4);
                    Array.Copy(pbyBufIn, 1, achKeyData, 21, 2); // random key part sent from remote client
                    rawHash = md5.ComputeHash(achKeyData);
                }
                else if (byCurrentTry == 2)
                {
                    // kad packet with ReceiverKey as key
                    bKad            = true;
                    bKadRecvKeyUsed = true;
                    if (MuleApplication.Instance.KadEngine.Preference != null)
                    {
                        byte[] achKeyData = new byte[6];
                        Array.Copy(BitConverter.GetBytes(MuleApplication.Instance.KadEngine.Preference.GetUDPVerifyKey(dwIP)),
                                   achKeyData, 4);
                        Array.Copy(pbyBufIn, 1, achKeyData, 4, 2); // random key part sent from remote client
                        rawHash = md5.ComputeHash(achKeyData);
                    }
                }
                else
                {
                    Debug.Assert(false);
                }

                MuleUtilities.RC4CreateKey(rawHash, 16, ref keyReceiveKey, true);
                byte[] outBuf = new byte[4];
                MuleUtilities.RC4Crypt(pbyBufIn, 3, outBuf, 0, 4, keyReceiveKey);
                dwIP         = BitConverter.ToUInt32(outBuf, 0);
                byCurrentTry = (byte)((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)
                {
                    MpdUtilities.DebugLog(
                        string.Format("Received obfuscated UDP packet from clientIP: {0} with wrong key marker bits (kad packet, ed2k bit)", MpdUtilities.IP2String(dwIP)));
                }
                else if (bKad && !bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) != 0)
                {
                    MpdUtilities.DebugLog(
                        string.Format("Received obfuscated UDP packet from clientIP: {0} with wrong key marker bits (kad packet, nodeid key, recvkey bit)", MpdUtilities.IP2String(dwIP)));
                }
                else if (bKad && bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) == 0)
                {
                    MpdUtilities.DebugLog(
                        string.Format("Received obfuscated UDP packet from clientIP: {0} with wrong key marker bits (kad packet, recvkey key, nodeid bit)", MpdUtilities.IP2String(dwIP)));
                }

                byte   byPadLen;
                byte[] outBuf = new byte[1];
                MuleUtilities.RC4Crypt(pbyBufIn, 7, outBuf, 0, 1, keyReceiveKey);
                byPadLen = outBuf[0];

                nResult -= CRYPT_HEADER_WITHOUTPADDING;
                if (nResult <= byPadLen)
                {
                    MpdUtilities.DebugLogError(
                        string.Format("Invalid obfuscated UDP packet from clientIP: {0}, Paddingsize ({1}) larger than received bytes",
                                      MpdUtilities.IP2String(dwIP), byPadLen));
                    return(nBufLen); // pass through, let the Receivefunction do the errorhandling on this junk
                }
                if (byPadLen > 0)
                {
                    MuleUtilities.RC4Crypt(null, null, byPadLen, keyReceiveKey);
                }
                nResult -= byPadLen;

                if (bKad)
                {
                    if (nResult <= 8)
                    {
                        MpdUtilities.DebugLogError(
                            string.Format("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: {0}",
                                          MpdUtilities.IP2String(dwIP)));
                        return(nBufLen); // pass through, let the Receivefunction do the errorhandling on this junk;
                    }
                    // read the verify keys
                    outBuf = new byte[4];
                    MuleUtilities.RC4Crypt(pbyBufIn, (int)(CRYPT_HEADER_WITHOUTPADDING + byPadLen),
                                           outBuf, 0, 4, keyReceiveKey);
                    nReceiverVerifyKey = BitConverter.ToUInt32(outBuf, 0);
                    MuleUtilities.RC4Crypt(pbyBufIn, (int)(CRYPT_HEADER_WITHOUTPADDING + byPadLen + 4),
                                           outBuf, 0, 4, keyReceiveKey);
                    nSenderVerifyKey = BitConverter.ToUInt32(outBuf, 0);
                    nResult         -= 8;
                }

                ppbyBufOut = new byte[nResult];
                Array.Copy(pbyBufIn, (nBufLen - nResult), ppbyBufOut, 0, nResult);

                MuleUtilities.RC4Crypt(ppbyBufOut, ppbyBufOut, (uint)nResult, keyReceiveKey);
                MuleApplication.Instance.Statistics.AddDownDataOverheadCrypt((uint)(nBufLen - nResult));
                //DEBUG_ONLY( MpdUtilities.DebugLog(("Received obfuscated UDP packet from clientIP: %s, Key: %s, RKey: %u, SKey: %u"), MpdUtilities.IP2String(dwIP), bKad ? (bKadRecvKeyUsed ? ("ReceiverKey") : ("NodeID")) : ("UserHash")
                //	, nReceiverVerifyKey != 0 ? *nReceiverVerifyKey : 0, nSenderVerifyKey != 0 ? *nSenderVerifyKey : 0) );
                return(nResult); // done
            }
            else
            {
                MpdUtilities.DebugLogWarning(
                    string.Format("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: {0}, Possible RecvKey: {1}",
                                  MpdUtilities.IP2String(dwIP), MuleApplication.Instance.KadEngine.Preference.GetUDPVerifyKey(dwIP)));
                return(nBufLen); // pass through, let the Receivefunction do the errorhandling on this junk
            }
        }
Пример #3
0
        public override int Receive(byte[] lpBuf, int offset, int nBufLen, SocketFlags nFlags)
        {
            obfuscationBytesReceived_ = base.Receive(lpBuf, offset, nBufLen, nFlags);

            fullReceive_ = obfuscationBytesReceived_ == (uint)nBufLen;

            if (obfuscationBytesReceived_ == SOCKET_ERROR || obfuscationBytesReceived_ <= 0)
            {
                return(obfuscationBytesReceived_);
            }
            switch (streamCryptState_)
            {
            case StreamCryptStateEnum.ECS_NONE:     // disabled, just pass it through
                return(obfuscationBytesReceived_);

            case StreamCryptStateEnum.ECS_PENDING:
            case StreamCryptStateEnum.ECS_PENDING_SERVER:
                Debug.Assert(false);
                MpdUtilities.DebugLogError(("CEncryptedStreamSocket Received data before sending on outgoing connection"));
                streamCryptState_ = StreamCryptStateEnum.ECS_NONE;
                return(obfuscationBytesReceived_);

            case StreamCryptStateEnum.ECS_UNKNOWN:
            {
                int  nRead         = 1;
                bool bNormalHeader = false;
                switch (lpBuf[offset])
                {
                case MuleConstants.PROTOCOL_EDONKEYPROT:
                case MuleConstants.PROTOCOL_PACKEDPROT:
                case MuleConstants.PROTOCOL_EMULEPROT:
                    bNormalHeader = true;
                    break;
                }
                if (!bNormalHeader)
                {
                    StartNegotiation(false);
                    int nNegRes = Negotiate(lpBuf, offset + nRead, obfuscationBytesReceived_ - nRead);
                    if (nNegRes == (-1))
                    {
                        return(0);
                    }
                    nRead += nNegRes;
                    if (nRead != obfuscationBytesReceived_)
                    {
                        // 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)
                        MpdUtilities.DebugLogError(("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (1)"), DbgGetIPString());
                        OnError(Convert.ToInt32(EMSocketErrorCodeEnum.ERR_ENCRYPTION));
                    }
                    return(0);
                }
                else
                {
                    // doesn't seems to be encrypted
                    streamCryptState_ = StreamCryptStateEnum.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 (MuleApplication.Instance.Preference.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

                        IPEndPoint remote  = RemoteEndPoint as IPEndPoint;
                        uint       address = BitConverter.ToUInt32(remote.Address.GetAddressBytes(), 0);

                        if (MuleApplication.Instance.Preference.IsClientCryptLayerRequiredStrict ||
                            (!MuleApplication.Instance.ServerConnect.AwaitingTestFromIP(address) &&
                             !MuleApplication.Instance.ClientList.IsKadFirewallCheckIP(address)))
                        {
                            MpdUtilities.AddDebugLogLine(EDebugLogPriority.DLP_DEFAULT, false, ("Rejected incoming connection because Obfuscation was required but not used %s"), DbgGetIPString());
                            OnError(Convert.ToInt32(EMSocketErrorCodeEnum.ERR_ENCRYPTION_NOTALLOWED));
                            return(0);
                        }
                        else
                        {
                            MpdUtilities.AddDebugLogLine(EDebugLogPriority.DLP_DEFAULT, false, ("Incoming unencrypted firewallcheck connection permitted despite RequireEncryption setting  - %s"), DbgGetIPString());
                        }
                    }

                    return(obfuscationBytesReceived_);        // buffer was unchanged, we can just pass it through
                }
            }

            case StreamCryptStateEnum.ECS_ENCRYPTING:
                // basic obfuscation enabled and set, so decrypt and pass along
                MuleUtilities.RC4Crypt(lpBuf, offset, lpBuf, offset, Convert.ToUInt32(obfuscationBytesReceived_), rc4ReceiveKey_);
                return(obfuscationBytesReceived_);

            case StreamCryptStateEnum.ECS_NEGOTIATING:
            {
                int nRead = Negotiate(lpBuf, offset, obfuscationBytesReceived_);
                if (nRead == (-1))
                {
                    return(0);
                }
                else if (nRead != obfuscationBytesReceived_ &&
                         streamCryptState_ != StreamCryptStateEnum.ECS_ENCRYPTING)
                {
                    // this means we have more data then the current negotiation step required (or there is a bug) and this should never happen
                    MpdUtilities.DebugLogError(("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (2)"), DbgGetIPString());
                    OnError(Convert.ToInt32(EMSocketErrorCodeEnum.ERR_ENCRYPTION));
                    return(0);
                }
                else if (nRead != (uint)obfuscationBytesReceived_ && streamCryptState_ == StreamCryptStateEnum.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
                    MpdUtilities.DebugLogWarning(("CEncryptedStreamSocket: Client %s has finished the handshake but also sent payload on a outgoing connection"), DbgGetIPString());
                    Array.Copy(lpBuf, offset + nRead, lpBuf, offset + 0, obfuscationBytesReceived_ - nRead);
                    return(obfuscationBytesReceived_ - nRead);
                }
                else
                {
                    return(0);
                }
            }

            default:
                Debug.Assert(false);
                return(obfuscationBytesReceived_);
            }
        }