/// <summary> /// Called when a connection comes in on the CDKey server /// </summary> /// known messages /// \ka\ = keep alive from the game server every 20s, we don't care about this /// \auth\ ... = authenticate cd key, this is what we care about /// \disc\ ... = disconnect cd key, because there's checks if the cd key is in use, which we don't care about really, but we could if we wanted to /// </remarks> protected override void ProcessAccept(GamespyUdpPacket Packet) { // If we dont reply, we must manually release the EventArgs back to the pool bool replied = false; try { // Decrypt message IPEndPoint remote = (IPEndPoint)Packet.AsyncEventArgs.RemoteEndPoint; string decrypted = Xor(Encoding.UTF8.GetString(Packet.BytesRecieved)).Trim('\\'); // Ignore keep alive pings if (!decrypted.StartsWith("ka")) { Dictionary <string, string> recv = ConvertToKeyValue(decrypted.Split('\\')); if (recv.ContainsKey("auth") && recv.ContainsKey("resp") && recv.ContainsKey("skey")) { if (Debugging) { DebugLog.Write("CDKey Check Requested from: {0}:{1}", remote.Address, remote.Port); } // Normally you would check the CD key database for the CD key MD5, but we arent Gamespy, we dont care string reply = String.Format(@"\uok\\cd\{0}\skey\{1}", recv["resp"].Substring(0, 32), recv["skey"]); // Set new packet contents, and send a reply Packet.SetBufferContents(Encoding.UTF8.GetBytes(Xor(reply))); base.ReplyAsync(Packet); replied = true; } else if (recv.ContainsKey("disc")) { // Handle, User disconnected from server } else { if (Debugging) { DebugLog.Write("Incomplete or Invalid CDKey Packet Received: " + decrypted); } } } } catch (Exception E) { Program.ErrorLog.Write("ERROR: [MasterServer.CDKeySocket_OnDataReceived] " + E.Message); } finally { // Release so that we can pool the EventArgs to be used on another connection if (!replied) { base.Release(Packet.AsyncEventArgs); } } }
/// <summary> /// Callback method for when the UDP Master socket recieves a connection /// </summary> protected override void ProcessAccept(GamespyUdpPacket Packet) { IPEndPoint remote = (IPEndPoint)Packet.AsyncEventArgs.RemoteEndPoint; // Need at least 5 bytes if (Packet.BytesRecieved.Length < 5) { base.Release(Packet.AsyncEventArgs); return; } // Handle request in a new thread Task.Run(() => { // If we dont reply, we must manually release the pool bool replied = false; try { // Both the clients and servers will send a Gamespy Available Heartbeat Check // When starting Battlefield 2, the client will send 7 heartbeat checks if (Packet.BytesRecieved[0] == 0x09 && Packet.BytesRecieved.SequenceEqual(BF2AvailableRequest)) { DebugLog.Write("BF2Available Called From {0}:{1}", remote.Address, remote.Port); // Send back a generic reply. Packet.SetBufferContents(BF2AvailableReply); base.ReplyAsync(Packet); replied = true; } else if (Packet.BytesRecieved[0] == 0x03 && Program.Config.GamespyEnableServerlist) { // === this is where server details come in, it starts with 0x03, it happens every 60 seconds or so // If we aren't validated (initial connection), send a challenge key if (!ParseServerDetails(remote, Packet.BytesRecieved.Skip(5).ToArray())) { DebugLog.Write("Sending Server Challenge to {0}:{1}", remote.Address, remote.Port); // this should be some sort of proper encrypted challenge, but for now i'm just going to hard code // it because I don't know how the encryption works... byte[] uniqueId = Packet.BytesRecieved.Skip(1).Take(4).ToArray(); Packet.SetBufferContents(new byte[] { 0xfe, 0xfd, 0x01, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3], 0x44, 0x3d, 0x73, 0x7e, 0x6a, 0x59, 0x30, 0x30, 0x37, 0x43, 0x39, 0x35, 0x41, 0x42, 0x42, 0x35, 0x37, 0x34, 0x43, 0x43, 0x00 }); base.ReplyAsync(Packet); replied = true; } } else if (Packet.BytesRecieved[0] == 0x01 && Program.Config.GamespyEnableServerlist) { // === this is a challenge response, it starts with 0x01 if (Packet.BytesRecieved.Skip(5).SequenceEqual(ServerValidateCode)) { DebugLog.Write("Server Challenge Recieved and Validated: {0}:{1}", remote.Address, remote.Port); // Send back a good response if we validate successfully if (ValidateServer(remote)) { byte[] uniqueId = Packet.BytesRecieved.Skip(1).Take(4).ToArray(); Packet.SetBufferContents(new byte[] { 0xfe, 0xfd, 0x0a, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3] }); base.ReplyAsync(Packet); replied = true; } } else { DebugLog.Write("Server Challenge Received and FAILED Validation: {0}:{1}", remote.Address, remote.Port); } } else if (Packet.BytesRecieved[0] == 0x08 && Program.Config.GamespyEnableServerlist) { // this is a server ping, it starts with 0x08, it happens every 20 seconds or so string key = String.Format("{0}:{1}", remote.Address, remote.Port); GameServer server; if (Servers.TryGetValue(key, out server) && server.IsValidated) { DebugLog.Write("Server Heartbeat Received: " + key); // Update Ping server.LastPing = DateTime.Now; Servers.AddOrUpdate(key, server, (k, old) => { return(server); }); } else { DebugLog.Write("Server Heartbeat Received from Unvalidated Server: " + key); } } } catch (Exception E) { Program.ErrorLog.Write("ERROR: [MasterUdpServer.ProcessAccept] " + E.Message); } // Release so that we can pool the EventArgs to be used on another connection if (!replied) { base.Release(Packet.AsyncEventArgs); } }); }
/// <summary> /// Callback method for when the UDP Master socket recieves a connection /// </summary> protected override void ProcessAccept(GamespyUdpPacket Packet) { IPEndPoint remote = (IPEndPoint)Packet.AsyncEventArgs.RemoteEndPoint; // Need at least 5 bytes if (Packet.BytesRecieved.Length < 5) { base.Release(Packet.AsyncEventArgs); return; } // Handle request in a new thread Task.Run(() => { // If we dont reply, we must manually release the pool bool replied = false; try { // Both the client and server will send an Gamespy Available Heartbeat Check if (Packet.BytesRecieved.SequenceEqual(BF2AvailableRequest)) { if (Debugging) { DebugLog.Write("BF2Available Called From {0}:{1}", remote.Address, remote.Port); } Packet.SetBufferContents(BF2AvailableReply); base.ReplyAsync(Packet); replied = true; } else if (Packet.BytesRecieved[0] == 0x03) { // this is where server details come in, it starts with 0x03, it happens every 60 seconds or so byte[] uniqueId = new byte[4]; Array.Copy(Packet.BytesRecieved, 1, uniqueId, 0, 4); // If we arent validated (initial connection), send a challenge key if (!ParseServerDetails(remote, Packet.BytesRecieved.Skip(5).ToArray())) { // this should be some sort of proper encrypted challenge, but for now i'm just going to hard code // it because I don't know how the encryption works... Packet.SetBufferContents(new byte[] { 0xfe, 0xfd, 0x01, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3], 0x44, 0x3d, 0x73, 0x7e, 0x6a, 0x59, 0x30, 0x30, 0x37, 0x43, 0x39, 0x35, 0x41, 0x42, 0x42, 0x35, 0x37, 0x34, 0x43, 0x43, 0x00 }); base.ReplyAsync(Packet); replied = true; } } else if (Packet.BytesRecieved[0] == 0x01) { // this is a challenge response, it starts with 0x01 byte[] uniqueId = new byte[4]; Array.Copy(Packet.BytesRecieved, 1, uniqueId, 0, 4); // confirm against the hardcoded challenge byte[] clientResponse = new byte[ServerValidateCode.Length]; Array.Copy(Packet.BytesRecieved, 5, clientResponse, 0, clientResponse.Length); // if we validate, reply back a good response if (clientResponse.SequenceEqual(ServerValidateCode)) { if (Debugging) { DebugLog.Write("Server Challenge... Validated: {0}:{1}", remote.Address, remote.Port); } // Send back a good response if we validate successfully Packet.SetBufferContents(new byte[] { 0xfe, 0xfd, 0x0a, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3] }); base.ReplyAsync(Packet); replied = true; ValidateServer(remote); } else if (Debugging) { DebugLog.Write("Server Challenge... FAILED: {0}:{1}", remote.Address, remote.Port); } } else if (Packet.BytesRecieved[0] == 0x08) { // this is a server ping, it starts with 0x08, it happens every 20 seconds or so string key = String.Format("{0}:{1}", remote.Address, remote.Port); GameServer server; if (Servers.TryGetValue(key, out server) && server.IsValidated) { if (Debugging) { DebugLog.Write("Server Heartbeat Received: " + key); } // Update Ping server.LastPing = DateTime.Now; Servers.AddOrUpdate(key, server, (k, old) => { return(server); }); } else if (Debugging) { DebugLog.Write("Server Heartbeat Received from Unvalidated Server: " + key); } } } catch (Exception E) { Program.ErrorLog.Write("ERROR: [UdpSock_DataReceived] " + E.Message); } finally { // Release so that we can pool the EventArgs to be used on another connection if (!replied) { base.Release(Packet.AsyncEventArgs); } } }); }