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(); }
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()); }
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(); }
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()); }
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); }
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); }
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); } }
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; } }
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); }
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); }
public void SetSymmetricCipher(SymmetricCipher theCipher) { SymmetricCipher = theCipher; }
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); }