Skip to content

Instantly share code, notes, and snippets.

@Lachee
Created November 19, 2018 09:55
Show Gist options
  • Save Lachee/fecafd7a3e12ee5714b682e0cfbccb85 to your computer and use it in GitHub Desktop.
Save Lachee/fecafd7a3e12ee5714b682e0cfbccb85 to your computer and use it in GitHub Desktop.
C# Dotnet Steam RCON Client
public class Packet
{
public int ID { get; set; }
public string Body { get; set; }
public PacketType Type { get; set; }
public enum PacketType
{
ServerdataAuth = 3,
ServerdataAuthResponse = 2,
ServerdataExecuteCommand = 2,
ServerdataResponseValue = 0
}
public static async Task<Packet> FromStream(Stream stream, int count)
{
int id, type;
string body;
byte[] intbuff = new byte[sizeof(int)];
byte[] stringbuff = new byte[count - 10];
byte[] nullbuff = new byte[2];
await stream.ReadAsync(intbuff, 0, intbuff.Length);
id = BitConverter.ToInt32(intbuff, 0);
await stream.ReadAsync(intbuff, 0, intbuff.Length);
type = BitConverter.ToInt32(intbuff, 0);
await stream.ReadAsync(stringbuff, 0, stringbuff.Length);
body = System.Text.Encoding.ASCII.GetString(stringbuff);
await stream.ReadAsync(nullbuff, 0, nullbuff.Length);
return new Packet()
{
ID = id,
Type = type == 2 ? PacketType.ServerdataAuthResponse : (PacketType)type,
Body = body
};
}
public async Task ToStream(Stream stream)
{
byte[] bodyBuffer = System.Text.Encoding.ASCII.GetBytes(Body);
int size = bodyBuffer.Length + 10;
await stream.WriteAsync(BitConverter.GetBytes(size), 0, sizeof(int));
await stream.WriteAsync(BitConverter.GetBytes(ID), 0, sizeof(int));
await stream.WriteAsync(BitConverter.GetBytes((int) Type), 0, sizeof(int));
await stream.WriteAsync(bodyBuffer, 0, bodyBuffer.Length);
await stream.WriteAsync(new byte[2], 0, 2);
}
}
public class RconClient
{
public string Address { get; }
public int Port { get; }
private string _password;
public RconClient(string address, int port, string password = null)
{
Address = address;
Port = port;
_password = password;
}
public async Task<RconResponse> Execute(string command)
{
try
{
int sequence = 10;
using (var tcp = new TcpClient())
{
//Connect to the TCP and prepare the stream
await tcp.ConnectAsync(Address, Port);
using (var stream = tcp.GetStream())
{
//Write the authentication packet
int authID = sequence++;
await new Packet()
{
ID = authID,
Type = Packet.PacketType.ServerdataAuth,
Body = _password
}.ToStream(stream);
//Make sure its all valid
bool receivedAuthPacket = false;
bool isAuthenticated = false;
//Prepare a buffer and read all the authorization packets.
byte[] sizebuff = new byte[sizeof(int)];
while (!receivedAuthPacket)
{
await stream.ReadAsync(sizebuff, 0, sizebuff.Length);
var authResponsePacket = await Packet.FromStream(stream, BitConverter.ToInt32(sizebuff, 0));
if (authResponsePacket.Type == Packet.PacketType.ServerdataAuthResponse)
{
receivedAuthPacket = true;
isAuthenticated = authResponsePacket.ID == authID;
}
}
//Make sure we are authorized
if (!isAuthenticated)
{
return new RconResponse()
{
Message = "Invalid Authorization",
Successful = false
};
}
//Write the command packet
await new Packet()
{
ID = sequence++,
Type = Packet.PacketType.ServerdataExecuteCommand,
Body = command
}.ToStream(stream);
//Read its response.
await stream.ReadAsync(sizebuff, 0, sizebuff.Length);
var responsePacket = await Packet.FromStream(stream, BitConverter.ToInt32(sizebuff, 0));
return new RconResponse()
{
Response = responsePacket.Body,
Successful = true
};
}
}
}
catch (Exception e)
{
return new RconResponse()
{
Message = e.Message,
Successful = false
};
}
}
}
public struct RconResponse
{
public string Response { get; set; }
public string Message { get; set; }
public bool Successful { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment