Example #1
0
        protected void HandleConnectAccept(IPEndPoint address, BitStream stream)
        {
            var nonce       = new Nonce();
            var serverNonce = new Nonce();

            nonce.Read(stream);
            serverNonce.Read(stream);

            var decryptPos = stream.GetBytePosition();

            stream.SetBytePosition(decryptPos);

            var conn = FindPendingConnection(address);

            if (conn == null || conn.ConnectionState != NetConnectionState.AwaitingConnectResponse)
            {
                return;
            }

            var cParams = conn.GetConnectionParameters();

            if (cParams.Nonce != nonce || cParams.ServerNonce != serverNonce)
            {
                return;
            }

            if (cParams.UsingCrypto)
            {
                var theCipher = new SymmetricCipher(cParams.SharedSecret);

                if (!stream.DecryptAndCheckHash(NetConnection.MessageSignatureBytes, decryptPos, theCipher))
                {
                    return;
                }
            }

            stream.Read(out uint recvSequence);
            conn.SetInitialRecvSequence(recvSequence);

            string errorString = null;

            if (!conn.ReadConnectAccept(stream, ref errorString))
            {
                RemovePendingConnection(conn);
                return;
            }

            if (cParams.UsingCrypto)
            {
                stream.Read(SymmetricCipher.KeySize, cParams.InitVector);

                conn.SetSymmetricCipher(new SymmetricCipher(cParams.SymmetricKey, cParams.InitVector));
            }

            AddConnection(conn);
            RemovePendingConnection(conn);

            conn.ConnectionState = NetConnectionState.Connected;
            conn.OnConnectionEstablished();
        }
Example #2
0
        protected void SendConnectAccept(NetConnection conn)
        {
            var stream = new PacketStream();

            stream.Write((byte)PacketType.ConnectAccept);

            var cParams = conn.GetConnectionParameters();

            cParams.Nonce.Write(stream);
            cParams.ServerNonce.Write(stream);

            var encryptPos = stream.GetBytePosition();

            stream.SetBytePosition(encryptPos);

            stream.Write(conn.GetInitialSendSequence());

            conn.WriteConnectAccept(stream);

            if (cParams.UsingCrypto)
            {
                stream.Write(SymmetricCipher.KeySize, cParams.InitVector);

                var theCipher = new SymmetricCipher(cParams.SharedSecret);

                stream.HashAndEncrypt(NetConnection.MessageSignatureBytes, encryptPos, theCipher);
            }

            stream.SendTo(Socket, conn.GetNetAddress());
        }
Example #3
0
        protected void SendPunchPackets(NetConnection conn)
        {
            var cParams = conn.GetConnectionParameters();

            var stream = new PacketStream();

            stream.Write((byte)PacketType.Punch);

            if (cParams.IsInitiator)
            {
                cParams.Nonce.Write(stream);
            }
            else
            {
                cParams.ServerNonce.Write(stream);
            }

            var encryptPos = stream.GetBytePosition();

            stream.SetBytePosition(encryptPos);

            if (cParams.IsInitiator)
            {
                cParams.ServerNonce.Write(stream);
            }
            else
            {
                cParams.Nonce.Write(stream);

                if (stream.WriteFlag(RequiresKeyExchange || (cParams.RequestKeyExchange && PrivateKey != null)))
                {
                    stream.Write(stream.WriteFlag(cParams.RequestCertificate && Certificate != null) ? Certificate : PrivateKey.GetPublicKey());
                }
            }

            var theCipher = new SymmetricCipher(cParams.ArrangedSecret);

            stream.HashAndEncrypt(NetConnection.MessageSignatureBytes, encryptPos, theCipher);

            foreach (var ep in cParams.PossibleAddresses)
            {
                stream.SendTo(Socket, ep);

                Console.WriteLine("Sending punch packet ({0}, {1}) to {2}", Convert.ToBase64String(cParams.Nonce.Data), Convert.ToBase64String(cParams.ServerNonce.Data), ep);
            }

            ++conn.ConnectSendCount;
            conn.ConnectLastSendTime = GetCurrentTime();
        }
Example #4
0
        protected void SendArrangedConnectRequest(NetConnection conn)
        {
            var stream = new PacketStream();

            stream.Write((byte)PacketType.ArrangedConnectRequest);

            var cParams = conn.GetConnectionParameters();

            cParams.Nonce.Write(stream);

            var encryptPos      = stream.GetBytePosition();
            var innerEncryptPos = 0U;

            stream.SetBytePosition(encryptPos);

            cParams.ServerNonce.Write(stream);

            if (stream.WriteFlag(cParams.UsingCrypto))
            {
                stream.Write(cParams.PrivateKey.GetPublicKey());

                innerEncryptPos = stream.GetBytePosition();
                stream.SetBytePosition(innerEncryptPos);

                stream.Write(SymmetricCipher.KeySize, cParams.SymmetricKey);
            }

            stream.WriteFlag(cParams.DebugObjectSizes);
            stream.Write(conn.GetInitialSendSequence());

            conn.WriteConnectRequest(stream);

            if (innerEncryptPos > 0)
            {
                var theCipher = new SymmetricCipher(cParams.SharedSecret);

                stream.HashAndEncrypt(NetConnection.MessageSignatureBytes, innerEncryptPos, theCipher);
            }

            var theCipher2 = new SymmetricCipher(cParams.ArrangedSecret);

            stream.HashAndEncrypt(NetConnection.MessageSignatureBytes, encryptPos, theCipher2);

            ++conn.ConnectSendCount;
            conn.ConnectLastSendTime = GetCurrentTime();

            stream.SendTo(Socket, conn.GetNetAddress());
        }
Example #5
0
        protected void WriteRawPacket(BitStream stream, NetPacketType packetType)
        {
            WritePacketHeader(stream, packetType);

            if (packetType == NetPacketType.DataPacket)
            {
                var note = AllocNotify();

                ++NumNotifies;

                if (NotifyQueueHead == null)
                {
                    NotifyQueueHead = note;
                }
                else
                {
                    NotifyQueueTail.NextPacket = note;
                }

                NotifyQueueTail = note;

                note.NextPacket = null;
                note.SendTime   = Interface.GetCurrentTime();

                WritePacketRateInfo(stream, note);

                //var start = stream.GetBitPosition();

                stream.SetStringTable(StringTable);

                //Console.WriteLine("NetConnection {0}: START {1}", NetAddress, GetClassName());

                WritePacket(stream, note);

                //Console.WriteLine("NetConnection {0}: END {1} - {2} bits", NetAddress, GetClassName(), stream.GetBitPosition() - start);
            }

            if (SymmetricCipher == null)
            {
                return;
            }

            SymmetricCipher.SetupCounter(LastSendSeq, LastSeqRecvd, (uint)packetType, 0U);

            stream.HashAndEncrypt(MessageSignatureBytes, PacketHeaderByteSize, SymmetricCipher);
        }
Example #6
0
        protected void HandleDisconnect(IPEndPoint client, BitStream reader)
        {
            var conn = FindConnection(client);

            if (conn == null)
            {
                return;
            }

            var cParams = conn.GetConnectionParameters();

            var nonce = new Nonce();

            nonce.Read(reader);

            var serverNonce = new Nonce();

            serverNonce.Read(reader);

            if (nonce != cParams.Nonce || serverNonce != cParams.ServerNonce)
            {
                return;
            }

            var decryptPos = reader.GetBytePosition();

            reader.SetBytePosition(decryptPos);

            if (cParams.UsingCrypto)
            {
                var theCipher = new SymmetricCipher(cParams.SharedSecret);

                if (!reader.DecryptAndCheckHash(NetConnection.MessageSignatureBytes, decryptPos, theCipher))
                {
                    return;
                }
            }

            reader.ReadString(out string reason);

            conn.ConnectionState = NetConnectionState.Disconnected;
            conn.OnConnectionTerminated(TerminationReason.ReasonRemoteDisconnectPacket, reason);

            RemoveConnection(conn);
        }
Example #7
0
        public void Disconnect(NetConnection conn, TerminationReason reason, string reasonString)
        {
            if (conn.ConnectionState == NetConnectionState.AwaitingChallengeResponse ||
                conn.ConnectionState == NetConnectionState.AwaitingConnectResponse)
            {
                conn.OnConnectTerminated(reason, reasonString);
                RemovePendingConnection(conn);
            }
            else if (conn.ConnectionState == NetConnectionState.Connected)
            {
                conn.ConnectionState = NetConnectionState.Disconnected;
                conn.OnConnectionTerminated(reason, reasonString);

                if (conn.IsNetworkConnection())
                {
                    var stream = new PacketStream();
                    stream.Write((byte)PacketType.Disconnect);

                    var cParams = conn.GetConnectionParameters();

                    cParams.Nonce.Write(stream);
                    cParams.ServerNonce.Write(stream);

                    var encryptPos = stream.GetBytePosition();
                    stream.SetBytePosition(encryptPos);

                    stream.WriteString(reasonString);

                    if (cParams.UsingCrypto)
                    {
                        var theCipher = new SymmetricCipher(cParams.SharedSecret);

                        stream.HashAndEncrypt(NetConnection.MessageSignatureBytes, encryptPos, theCipher);
                    }

                    stream.SendTo(Socket, conn.GetNetAddress());
                }

                RemoveConnection(conn);
            }
        }
Example #8
0
        protected void HandlePunch(IPEndPoint address, BitStream stream)
        {
            var firstNonce = new Nonce();

            firstNonce.Read(stream);

            Console.WriteLine("Received punch packet from {0} - {1}", address, Convert.ToBase64String(firstNonce.Data));

            var           found = false;
            NetConnection conn  = null;

            foreach (var pair in PendingConnections)
            {
                conn = pair.Value;
                var cParams = conn.GetConnectionParameters();

                if (conn.ConnectionState != NetConnectionState.SendingPunchPackets)
                {
                    continue;
                }

                if ((cParams.IsInitiator && firstNonce != cParams.ServerNonce) || (!cParams.IsInitiator && firstNonce != cParams.Nonce))
                {
                    continue;
                }

                if (cParams.PossibleAddresses.Contains(address))
                {
                    if (cParams.IsInitiator)
                    {
                        found = true;
                        break;
                    }

                    continue;
                }

                var cont = cParams.PossibleAddresses.Any(ep => ep.Address.Equals(address.Address) && ep.AddressFamily == address.AddressFamily);

                if (!cont)
                {
                    continue;
                }

                if (cParams.PossibleAddresses.Count < 5)
                {
                    cParams.PossibleAddresses.Add(address);
                }

                if (cParams.IsInitiator)
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                return;
            }

            var cParam    = conn.GetConnectionParameters();
            var theCipher = new SymmetricCipher(cParam.ArrangedSecret);

            if (stream.DecryptAndCheckHash(NetConnection.MessageSignatureBytes, stream.GetBytePosition(), theCipher))
            {
                return;
            }

            var nextNonce = new Nonce();

            nextNonce.Read(stream);

            if (nextNonce != cParam.Nonce)
            {
                return;
            }

            if (stream.ReadFlag())
            {
                if (stream.ReadFlag())
                {
                    cParam.Certificate = new Certificate(stream);
                    if (!cParam.Certificate.IsValid() || !conn.ValidateCertificate(cParam.Certificate, true))
                    {
                        return;
                    }

                    cParam.PublicKey = cParam.Certificate.GetPublicKey();
                }
                else
                {
                    cParam.PublicKey = new AsymmetricKey(stream);
                    if (!cParam.PublicKey.IsValid() || !conn.ValidatePublicKey(cParam.PublicKey, true))
                    {
                        return;
                    }
                }

                if (PrivateKey == null || PrivateKey.GetKeySize() != cParam.PublicKey.GetKeySize())
                {
                    cParam.PrivateKey = new AsymmetricKey(cParam.PublicKey.GetKeySize());
                }
                else
                {
                    cParam.PrivateKey = PrivateKey;
                }

                cParam.SharedSecret = cParam.PrivateKey.ComputeSharedSecretKey(cParam.PublicKey);

                RandomUtil.Read(cParam.SymmetricKey, SymmetricCipher.KeySize);

                cParam.UsingCrypto = true;
            }
        }
Example #9
0
        protected void HandleConnectRequest(IPEndPoint address, BitStream stream)
        {
            if (!AllowConnections)
            {
                return;
            }

            var cParams = new ConnectionParameters();

            cParams.Nonce.Read(stream);
            cParams.ServerNonce.Read(stream);
            stream.Read(out cParams.ClientIdentity);

            if (cParams.ClientIdentity != ComputeClientIdentityToken(address, cParams.Nonce))
            {
                return;
            }

            stream.Read(out cParams.PuzzleDifficulty);
            stream.Read(out cParams.PuzzleSolution);


            var connect = FindConnection(address);

            if (connect != null)
            {
                var cp = connect.GetConnectionParameters();

                if (cp.Nonce == cParams.Nonce && cp.ServerNonce == cParams.ServerNonce)
                {
                    SendConnectAccept(connect);
                    return;
                }
            }

            var result = PuzzleManager.CheckSolution(cParams.PuzzleSolution, cParams.Nonce, cParams.ServerNonce, cParams.PuzzleDifficulty, cParams.ClientIdentity);

            if (result != ErrorCode.Success)
            {
                SendConnectReject(cParams, address, "Puzzle");
                return;
            }

            if (stream.ReadFlag())
            {
                if (PrivateKey == null)
                {
                    return;
                }

                cParams.UsingCrypto = true;
                cParams.PublicKey   = new AsymmetricKey(stream);
                cParams.PrivateKey  = PrivateKey;

                var decryptPos = stream.GetBytePosition();

                stream.SetBytePosition(decryptPos);

                cParams.SharedSecret = cParams.PrivateKey.ComputeSharedSecretKey(cParams.PublicKey);

                var theCipher = new SymmetricCipher(cParams.SharedSecret);

                if (!stream.DecryptAndCheckHash(NetConnection.MessageSignatureBytes, decryptPos, theCipher))
                {
                    return;
                }

                stream.Read(SymmetricCipher.KeySize, cParams.SymmetricKey);
                RandomUtil.Read(cParams.InitVector, SymmetricCipher.KeySize);
            }

            cParams.DebugObjectSizes = stream.ReadFlag();

            stream.Read(out uint connectSequence);

            if (connect != null)
            {
                Disconnect(connect, TerminationReason.ReasonSelfDisconnect, "NewConnection");
            }

            stream.ReadString(out string connectionClass);

            var conn = NetConnectionRep.Create(connectionClass);

            if (conn == null)
            {
                return;
            }

            conn.SetConnectionParameters(cParams);
            conn.SetNetAddress(address);
            conn.SetInitialRecvSequence(connectSequence);
            conn.SetInterface(this);

            if (cParams.UsingCrypto)
            {
                conn.SetSymmetricCipher(new SymmetricCipher(cParams.SymmetricKey, cParams.InitVector));
            }

            string errorString = null;

            if (!conn.ReadConnectRequest(stream, ref errorString))
            {
                SendConnectReject(cParams, address, errorString);
                return;
            }

            AddConnection(conn);

            conn.ConnectionState = NetConnectionState.Connected;
            conn.OnConnectionEstablished();

            SendConnectAccept(conn);
        }
Example #10
0
        protected void HandleArrangedConnectRequest(IPEndPoint client, BitStream reader)
        {
            var nonce = new Nonce();

            nonce.Read(reader);

            var oldConnection = FindConnection(client);

            if (oldConnection != null)
            {
                var cp = oldConnection.GetConnectionParameters();
                if (cp.Nonce == nonce)
                {
                    SendConnectAccept(oldConnection);
                    return;
                }
            }

            NetConnection conn  = null;
            var           found = false;

            foreach (var pair in PendingConnections)
            {
                conn = pair.Value;
                var cp = conn.GetConnectionParameters();

                if (conn.ConnectionState != NetConnectionState.SendingPunchPackets || cp.IsInitiator)
                {
                    continue;
                }

                if (nonce != cp.Nonce)
                {
                    continue;
                }

                if (cp.PossibleAddresses.Any(ep => ep.Address.Equals(client.Address) && ep.AddressFamily == client.AddressFamily))
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                return;
            }

            var cParams   = conn.GetConnectionParameters();
            var theCipher = new SymmetricCipher(cParams.ArrangedSecret);

            if (!reader.DecryptAndCheckHash(NetConnection.MessageSignatureBytes, reader.GetBytePosition(), theCipher))
            {
                return;
            }

            reader.SetBytePosition(reader.GetBytePosition());

            var serverNonce = new Nonce();

            serverNonce.Read(reader);
            if (serverNonce != cParams.ServerNonce)
            {
                return;
            }

            if (reader.ReadFlag())
            {
                if (PrivateKey == null)
                {
                    return;
                }

                cParams.UsingCrypto = true;
                cParams.PublicKey   = new AsymmetricKey(reader);
                cParams.PrivateKey  = PrivateKey;

                var decryptPos = reader.GetBytePosition();
                reader.SetBytePosition(decryptPos);

                cParams.SharedSecret = cParams.PrivateKey.ComputeSharedSecretKey(cParams.PublicKey);

                var theCipher2 = new SymmetricCipher(cParams.SharedSecret);

                if (!reader.DecryptAndCheckHash(NetConnection.MessageSignatureBytes, decryptPos, theCipher2))
                {
                    return;
                }

                reader.Read(NetConnection.MessageSignatureBytes, cParams.SymmetricKey);
                RandomUtil.Read(cParams.InitVector, SymmetricCipher.KeySize);
            }

            cParams.DebugObjectSizes = reader.ReadFlag();
            reader.Read(out uint connectSequence);

            if (oldConnection != null)
            {
                Disconnect(oldConnection, TerminationReason.ReasonSelfDisconnect, "");
            }

            conn.SetNetAddress(client);
            conn.SetInitialRecvSequence(connectSequence);

            if (cParams.UsingCrypto)
            {
                conn.SetSymmetricCipher(new SymmetricCipher(cParams.SymmetricKey, cParams.InitVector));
            }

            string errorString = null;

            if (!conn.ReadConnectRequest(reader, ref errorString))
            {
                SendConnectReject(cParams, client, errorString);
                RemovePendingConnection(conn);
                return;
            }

            AddConnection(conn);

            RemovePendingConnection(conn);

            conn.ConnectionState = NetConnectionState.Connected;
            conn.OnConnectionEstablished();

            SendConnectAccept(conn);
        }
Example #11
0
 public void SetSymmetricCipher(SymmetricCipher theCipher)
 {
     SymmetricCipher = theCipher;
 }
Example #12
0
        protected bool ReadPacketHeader(BitStream stream)
        {
            var packetType     = (NetPacketType)stream.ReadInt(2);
            var sequenceNumber = stream.ReadInt(5);

            /*var dataPacketFlag = */ stream.ReadFlag();
            sequenceNumber = sequenceNumber | (stream.ReadInt(SequenceNumberBitSize - 5) << 5);

            var highestAck = stream.ReadInt(AckSequenceNumberBitSize);
            var padBits    = stream.ReadInt(PacketHeaderPadBits);

            if (padBits != 0)
            {
                return(false);
            }

            sequenceNumber |= (uint)(LastSeqRecvd & SequenceNumberMask);
            if (sequenceNumber < LastSeqRecvd)
            {
                sequenceNumber += SequenceNumberWindowSize;
            }

            if (sequenceNumber - LastSeqRecvd > (MaxPacketWindowSize - 1))
            {
                return(false);
            }

            highestAck |= (uint)(HighestAckedSeq & AckSequenceNumberMask);
            if (highestAck < HighestAckedSeq)
            {
                highestAck += AckSequenceNumberWindowSize;
            }

            if (highestAck > LastSendSeq)
            {
                return(false);
            }

            if (SymmetricCipher != null)
            {
                SymmetricCipher.SetupCounter(sequenceNumber, highestAck, (uint)packetType, 0);

                if (!stream.DecryptAndCheckHash(MessageSignatureBytes, PacketHeaderByteSize, SymmetricCipher))
                {
                    Console.WriteLine("Packet failed crypto");
                    return(false);
                }
            }

            var ackByteCount = stream.ReadRangedU32(0, MaxAckByteCount);

            if (ackByteCount > MaxAckByteCount || packetType >= NetPacketType.InvalidPacketType)
            {
                return(false);
            }

            var ackMask      = new uint[MaxAckMaskSize];
            var ackWordCount = (ackByteCount + 3) >> 2;

            for (var i = 0U; i < ackWordCount; ++i)
            {
                ackMask[i] = stream.ReadInt((byte)(i == ackWordCount - 1 ? (ackByteCount - (i * 4)) * 8 : 32));
            }

            var sendDelay = (stream.ReadInt(8) << 3) + 4;

            var ackMaskShift = sequenceNumber - LastSeqRecvd;

            while (ackMaskShift > 32)
            {
                for (var i = MaxAckMaskSize - 1; i > 0; --i)
                {
                    AckMask[i] = AckMask[i - 1];
                }

                AckMask[0]    = 0;
                ackMaskShift -= 32;
            }

            var upShifted = packetType == NetPacketType.DataPacket ? 1U : 0U;

            for (var i = 0U; i < MaxAckMaskSize; ++i)
            {
                var nextShift = AckMask[i] >> (int)(32 - ackMaskShift);
                AckMask[i] = (AckMask[i] << (int)ackMaskShift) | upShifted;
                upShifted  = nextShift;
            }

            var notifyCount = highestAck - HighestAckedSeq;

            for (var i = 0U; i < notifyCount; ++i)
            {
                var notifyIndex = HighestAckedSeq + i + 1;

                var ackMaskBit  = (highestAck - notifyIndex) & 0x1FU;
                var ackMaskWord = (highestAck - notifyIndex) >> 5;

                var packetTransmitSuccess = (ackMask[ackMaskWord] & (1U << (int)ackMaskBit)) != 0U;

                HighestAckedSendTime = 0;
                HandleNotify(notifyIndex, packetTransmitSuccess);

                if (HighestAckedSendTime > 0)
                {
                    var roundTripDelta = Interface.GetCurrentTime() - (HighestAckedSendTime + (int)sendDelay);

                    RoundTripTime = RoundTripTime * 0.9f + roundTripDelta * 0.1f;

                    if (RoundTripTime < 0.0f)
                    {
                        RoundTripTime = 0.0f;
                    }
                }

                if (packetTransmitSuccess)
                {
                    LastRecvAckAck = LastSeqRecvdAtSend[notifyIndex & PacketWindowMask];
                }
            }

            if (sequenceNumber - LastRecvAckAck > MaxPacketWindowSize)
            {
                LastRecvAckAck = sequenceNumber - MaxPacketWindowSize;
            }

            HighestAckedSeq  = highestAck;
            PingSendCount    = 0;
            LastPingSendTime = 0;

            KeepAlive();

            var prevLastSequence = LastSeqRecvd;

            LastSeqRecvd = sequenceNumber;

            if (packetType == NetPacketType.PingPacket || (sequenceNumber - LastRecvAckAck > (MaxPacketWindowSize >> 1)))
            {
                SendAckPacket();
            }

            return(prevLastSequence != sequenceNumber && packetType == NetPacketType.DataPacket);
        }