// sends a connection challenge packet to the endpoint private void sendConnectionChallenge(NetcodePrivateConnectToken connectToken, EndPoint endpoint) { log("Sending connection challenge", NetcodeLogLevel.Debug); var challengeToken = new NetcodeChallengeToken(); challengeToken.ClientID = connectToken.ClientID; challengeToken.UserData = connectToken.UserData; ulong challengeSequence = nextChallengeSequenceNumber++; byte[] tokenBytes = BufferPool.GetBuffer(300); using (var tokenWriter = ByteArrayReaderWriter.Get(tokenBytes)) challengeToken.Write(tokenWriter); byte[] encryptedToken = BufferPool.GetBuffer(300); int encryptedTokenBytes; try { encryptedTokenBytes = PacketIO.EncryptChallengeToken(challengeSequence, tokenBytes, challengeKey, encryptedToken); } catch { BufferPool.ReturnBuffer(tokenBytes); BufferPool.ReturnBuffer(encryptedToken); return; } var challengePacket = new NetcodeConnectionChallengeResponsePacket(); challengePacket.ChallengeTokenSequence = challengeSequence; challengePacket.ChallengeTokenBytes = encryptedToken; var cryptIdx = encryptionManager.FindEncryptionMapping(endpoint, time); if (cryptIdx == -1) { return; } var cryptKey = encryptionManager.GetSendKey(cryptIdx); serializePacket(new NetcodePacketHeader() { PacketType = NetcodePacketType.ConnectionChallenge }, (writer) => { challengePacket.Write(writer); }, endpoint, cryptKey); BufferPool.ReturnBuffer(tokenBytes); BufferPool.ReturnBuffer(encryptedToken); }
private void processChallengePacket(NetcodePacketHeader header, int length, ByteArrayReaderWriter stream) { var decryptKey = serverToClientKey; var challengePacket = new NetcodeConnectionChallengeResponsePacket() { Header = header }; if (!challengePacket.Read(stream, length, decryptKey, connectToken.ProtocolID)) { return; } if (state == ClientState.SendingConnectionRequest) { this.challengeResponse = challengePacket; this.challengeResponse.Header.PacketType = NetcodePacketType.ChallengeResponse; // move onto sending challenge response timer = 0.0; connectionTimer = 0.0; changeState(ClientState.SendingChallengeResponse); } }
// process an incoming connection response packet private void processConnectionResponse(ByteArrayReaderWriter reader, NetcodePacketHeader header, int size, EndPoint sender) { log("Got connection response", NetcodeLogLevel.Debug); // encryption mapping was not registered, so don't bother int cryptIdx = encryptionManager.FindEncryptionMapping(sender, time); if (cryptIdx == -1) { log("No crytpo key for sender", NetcodeLogLevel.Debug); return; } // grab the decryption key and decrypt the packet var decryptKey = encryptionManager.GetReceiveKey(cryptIdx); var connectionResponsePacket = new NetcodeConnectionChallengeResponsePacket() { Header = header }; if (!connectionResponsePacket.Read(reader, size - (int)reader.ReadPosition, decryptKey, protocolID)) { log("Failed to decrypt packet", NetcodeLogLevel.Debug); return; } var challengeToken = new NetcodeChallengeToken(); if (!challengeToken.Read(connectionResponsePacket.ChallengeTokenBytes, connectionResponsePacket.ChallengeTokenSequence, challengeKey)) { log("Failed to read challenge token", NetcodeLogLevel.Debug); connectionResponsePacket.Release(); return; } // if a client from packet source IP / port is already connected, ignore the packet if (clientSlots.Any(x => x != null && x.RemoteEndpoint.Equals(sender))) { log("Client {0} already connected", NetcodeLogLevel.Debug, sender.ToString()); return; } // if a client with the same id is already connected, ignore the packet if (clientSlots.Any(x => x != null && x.ClientID == challengeToken.ClientID)) { log("Client ID {0} already connected", NetcodeLogLevel.Debug, challengeToken.ClientID); return; } // if the server is full, deny the connection int nextSlot = getFreeClientSlot(); if (nextSlot == -1) { log("Server full, denying connection", NetcodeLogLevel.Info); denyConnection(sender, encryptionManager.GetSendKey(cryptIdx)); return; } // assign the endpoint and client ID to a free client slot and set connected to true RemoteClient client = new RemoteClient(this); client.ClientID = challengeToken.ClientID; client.RemoteEndpoint = sender; client.Connected = true; client.replayProtection = new NetcodeReplayProtection(); // assign timeout to client client.timeoutSeconds = encryptionManager.GetTimeoutSeconds(cryptIdx); // assign client to a free slot client.ClientIndex = (uint)nextSlot; this.clientSlots[nextSlot] = client; encryptionManager.SetClientID(cryptIdx, client.ClientIndex); // copy user data so application can make use of it, and set confirmed to false client.UserData = challengeToken.UserData; client.Confirmed = false; client.Touch(time); // respond with a connection keep alive packet sendKeepAlive(client); }