private void Client_MessageReceived(RconClient sender, RconPacket packet) { switch (packet.Type) { case PacketType.SERVERDATA_AUTH: Authenticate(sender, packet); break; case PacketType.SERVERDATA_EXECCOMMAND: if (sender.IsAuthed) { HandleCommand(sender, packet); } else { sender.SendPacket(new RconPacket(packet.Id, PacketType.SERVERDATA_RESPONSE_VALUE, "Not authenticated")); } break; default: Log.Error($"Recieved an unsupported packet type {packet.Type}. Id: {packet.Id}"); sender.SendPacket(new RconPacket(packet.Id, PacketType.SERVERDATA_RESPONSE_VALUE, "Invalid packet type")); break; } }
public void SendPacket(RconPacket packet) { _outboundQueue.Enqueue(packet); //TODO: split if necessary //_outboundQueue.Enqueue(new RconPacket(packet.Id, PacketType.SERVERDATA_RESPONSE_VALUE, string.Empty)); if (!_isSending) { FlushQueueAsync().ConfigureAwait(false); } }
private void HandleCommand(RconClient sender, RconPacket packet) { var message = CommandHandler?.Invoke(packet.Body) ?? "No command handler defined on host."; var response = new RconPacket { Id = packet.Id, Type = PacketType.SERVERDATA_RESPONSE_VALUE, Body = message }; sender.SendPacket(response); }
private void Authenticate(RconClient sender, RconPacket packet) { var hash = Md5Util.HashString(packet.Body); if (_pwHash != null && hash.SequenceEqual(_pwHash)) { Log.Info($"{sender.RemoteEndPoint}: Authorized"); sender.SendPacket(new RconPacket(packet.Id, PacketType.SERVERDATA_AUTHRESPONSE, string.Empty)); sender.IsAuthed = true; } else { Log.Warn($"{sender.RemoteEndPoint}: Incorrect password attempt"); sender.SendPacket(new RconPacket(-1, PacketType.SERVERDATA_AUTHRESPONSE, string.Empty)); sender.IsAuthed = false; } }
public static RconPacket FromBytes(byte[] buffer, int offset, int length) { //TODO validate byte length var packet = new RconPacket(); packet.Size = BitConverter.ToInt32(buffer, offset); offset += sizeof(int); packet.Id = BitConverter.ToInt32(buffer, offset); offset += sizeof(int); packet.Type = (PacketType)BitConverter.ToInt32(buffer, offset); offset += sizeof(int); var readLength = packet.Size - (HEADER_SIZE + END_TERMINATION); packet.Body = Encoding.ASCII.GetString(buffer, offset, readLength); return(packet); }
private void Authenticate(RconClient sender, RconPacket packet) { var hash = Md5Util.HashString(packet.Body); if (_pwHash != null && hash.SequenceEqual(_pwHash)) { Log.Info($"{sender.RemoteEndPoint}: Authorized"); // Necessary to send an empty RESPONSE_VALUE before sending the AUTHRESPONSE, otherwise most RCON clients donĀ“t realize AUTH has been successfully. // See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#SERVERDATA_AUTH_RESPONSE // >> When the server receives an auth request, it will respond with an empty SERVERDATA_RESPONSE_VALUE, followed immediately by a SERVERDATA_AUTH_RESPONSE indicating whether authentication succeeded or failed. sender.SendPacket(new RconPacket(packet.Id, PacketType.SERVERDATA_RESPONSE_VALUE, string.Empty)); sender.SendPacket(new RconPacket(packet.Id, PacketType.SERVERDATA_AUTHRESPONSE, string.Empty)); sender.IsAuthed = true; } else { Log.Warn($"{sender.RemoteEndPoint}: Incorrect password attempt"); sender.SendPacket(new RconPacket(packet.Id, PacketType.SERVERDATA_RESPONSE_VALUE, string.Empty)); // same here by definition although most clients realized the wrong AUTH info sender.SendPacket(new RconPacket(-1, PacketType.SERVERDATA_AUTHRESPONSE, string.Empty)); sender.IsAuthed = false; } }
private void EndReceivePacket(IAsyncResult ar) { var receiveData = (Tuple <Socket, byte[]>)ar.AsyncState; var client = receiveData.Item1; var rconMessageBytes = receiveData.Item2; try { client.EndReceive(ar); Log.Debug($"Message: {string.Join("", rconMessageBytes.Select(x => x.ToString("x2")))}"); var rconMessage = RconPacket.FromBytes(rconMessageBytes, 0, rconMessageBytes.Length); Log.Debug($"Got packet: {rconMessage.Size} bytes\n Type: {rconMessage.Type:G}\n Id: {rconMessage.Id}\n Body: {rconMessage.Body}"); BeginReceivePacket(client); MessageReceived?.Invoke(this, rconMessage); } catch (Exception e) { OnConnectionException(e); } }