GameServer + packet types, we aren't parsing yet

This commit is contained in:
rfi 2023-10-08 21:12:01 +07:00
parent f753a0ffc4
commit 0eacd1bfe2
10 changed files with 306 additions and 5 deletions

View File

@ -8,7 +8,6 @@
<ItemGroup>
<PackageReference Include="Config.Net" Version="5.1.5" />
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
<PackageReference Include="MongoDB.Driver" Version="2.21.0" />
</ItemGroup>

View File

@ -33,7 +33,7 @@ namespace AscNet.Common.Database
public static Account Create(string username, string password)
{
if (collection.AsQueryable().FirstOrDefault(x => x.Username == username) is not null)
throw new ArgumentException("Username is already registered!", "username");
throw new ArgumentException("Username is already registered!", nameof(username));
Account account = new()
{

View File

@ -1,4 +1,6 @@
namespace AscNet.Common.Util
using System.Security.Cryptography;
namespace AscNet.Common.Util
{
public static class Crypto
{
@ -11,5 +13,78 @@
return encryptedData;
}
public static class HaruCrypt
{
private static readonly byte[] key = new byte[] { 103, 40, 227, 236, 173, 175, 148, 243, 66, 252, 58, 22, 68, 192, 159, 15, 187, 15, 15, 29, 209, 209, 212, 66, 104, 16, 252, 194, 227, 14, 116, 112, 196, 221, 5, 1, 4, 173, 165, 69, 45, 193, 95, 10, 67, 38, 167, 239, 96, 184, 133, 75, 152, 196, 36, 121, 251, 7, 73, 82, 219, 25, 118, 70, 153, 232, 120, 120, 147, 10, 88, 106, 214, 187, 216, 49, 224, 57, 1, 233, 110, 40, 65, 85, 246, 197, 4, 20, 56, 74, 245, 41, 63, 169, 188, 104, 89, 49, 115, 254, 100, 77, 79, 11, 148, 242, 95, 88, 241, 111, 48, 130, 169, 200, 224, 135, 121, 161, 72, 84, 5, 100, 135, 70, 141, 94, 244, 114, 58, 28, 87, 181, 205, 221, 154, 184, 197, 98, 210, 202, 252, 124, 144, 9, 112, 163, 24, 254, 119, 188, 5, 230, 40, 79, 171, 17, 156, 212, 134, 41, 79, 134, 26, 251, 123, 219, 191, 136, 21, 84, 192, 91, 24, 33, 68, 101, 85, 61, 186, 215, 191, 37, 45, 51, 117, 227, 14, 145, 56, 43, 32, 67, 48, 98, 192, 41, 136, 223, 50, 163, 97, 251, 174, 59, 59, 147, 237, 177, 31, 159, 52, 243, 245, 247, 148, 139, 21, 92, 139, 80, 47, 4, 105, 59, 227, 220, 180, 231, 176, 187, 205, 203, 148, 121, 98, 90, 87, 131, 245, 3, 63, 239, 57, 117, 102, 134, 40, 172, 60, 128, 108, 102, 216, 247, 133, 102 };
private static readonly RSACryptoServiceProvider rsa = new();
private static readonly byte[] signature = new byte[128];
#pragma warning disable SYSLIB0021 // Type or member is obsolete
private static readonly SHA1 sha = new SHA1CryptoServiceProvider();
#pragma warning restore SYSLIB0021 // Type or member is obsolete
private const string PUBLIC_KEY = "<RSAKeyValue><Modulus>kZE/f0ifi0DH3uP3KCWOPqTyQ3MsQKHf9X4Z65S36s226RkdkZL2kHTz20n+IlOvGChi3ByDMFLawlyB0MCW94WDnc1Mc/PtVKo6D8gBEcSvdjDbhC4Ly0f2hMHS/SNdGPMAMkEWGNvIvfuT1TEaWTPsxRLZbfASp2KPG7Wjdck=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
static HaruCrypt()
{
rsa.FromXmlString(PUBLIC_KEY);
}
public static void Encrypt(byte[] content)
{
Encrypt(content, 0, content.Length);
}
public static void Encrypt(byte[] content, int offset, int count)
{
int num = count % key.Length;
for (int i = 0; i < count; i++)
{
int num2 = i + offset;
int num3 = (int)content[num2];
num3 ^= (int)key[num];
if (i > 0)
{
num3 ^= (int)content[num2 - 1];
}
num3 ^= (int)key[i % key.Length];
int num4 = ((int)((i + 1 < count) ? content[num2 + 1] : 0) + count) % 8;
num3 = (num3 << 8 - num4 | num3 >> num4);
content[num2] = (byte)num3;
}
}
public static void Decrypt(byte[] content)
{
Decrypt(content, 0, content.Length);
}
private static void Decrypt(byte[] bytes, int offset, int count)
{
int num = count % key.Length;
for (int i = count - 1; i >= 0; i--)
{
int num2 = i + offset;
int num3 = (int)bytes[num2];
int num4 = ((int)((i + 1 < count) ? bytes[num2 + 1] : 0) + count) % 8;
num3 = (num3 >> 8 - num4 | num3 << num4);
num3 ^= (int)key[i % key.Length];
if (num2 > offset)
{
num3 ^= (int)bytes[num2 - 1];
}
num3 ^= (int)key[num];
bytes[num2] = (byte)num3;
}
}
private static bool Verify(byte[] content, ref int offset, ref int count)
{
Buffer.BlockCopy(content, offset, signature, 0, signature.Length);
offset += signature.Length;
count -= signature.Length;
byte[] hash = sha.ComputeHash(content, offset, count);
return rsa.VerifyHash(hash, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
}
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="2.5.129" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AscNet.Common\AscNet.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,76 @@
using MessagePack;
namespace AscNet.GameServer
{
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
[MessagePackObject(false)]
public class Packet
{
[Key(0)]
public int No;
[Key(1)]
public ContentType Type;
[Key(2)]
public byte[] Content;
public enum ContentType
{
Request,
Response,
Push,
Exception
}
[MessagePackObject(false)]
public class Request
{
[Key(0)]
public int Id;
[Key(1)]
public string Name;
[Key(2)]
public byte[] Content;
}
[MessagePackObject(false)]
public class Response
{
[Key(0)]
public int Id;
[Key(1)]
public string Name;
[Key(2)]
public byte[] Content;
}
[MessagePackObject(false)]
public class Push
{
[Key(0)]
public string Name;
[Key(1)]
public byte[] Content;
}
[MessagePackObject(false)]
public class Exception
{
[Key(0)]
public int Id;
[Key(1)]
public int Code;
[Key(2)]
public string Message;
}
}
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
}

View File

@ -0,0 +1,54 @@
using System.Net.Sockets;
using System.Net;
using AscNet.Common.Util;
namespace AscNet.GameServer
{
public class Server
{
public static readonly Logger c = new(nameof(GameServer), ConsoleColor.Cyan);
public readonly Dictionary<string, Session> Sessions = new();
private static Server? _instance;
private readonly TcpListener listener;
public static Server Instance
{
get
{
return _instance ??= new Server();
}
}
public Server()
{
listener = new(IPAddress.Parse("0.0.0.0"), Common.Common.config.GameServer.Port);
}
public void Start()
{
for (; ; )
{
try
{
listener.Start();
c.Log($"{nameof(GameServer)} started and listening on port {Common.Common.config.GameServer.Port}");
for (; ; )
{
TcpClient tcpClient = listener.AcceptTcpClient();
string id = tcpClient.Client.RemoteEndPoint!.ToString()!;
c.Warn($"{id} connected");
Sessions.Add(id, new Session(id, tcpClient));
}
}
catch (Exception ex)
{
c.Error("TCP listener error: " + ex.Message);
c.Log("Waiting 3 seconds before restarting...");
Thread.Sleep(3000);
}
}
}
}
}

View File

@ -0,0 +1,65 @@
using System.Net.Sockets;
using AscNet.Common.Util;
namespace AscNet.GameServer
{
public class Session
{
public readonly string id;
public readonly TcpClient client;
public readonly Logger c;
private long lastPacketTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// private ushort packetNo = 0;
public Session(string id, TcpClient tcpClient)
{
this.id = id;
client = tcpClient;
c = new(id, ConsoleColor.DarkGray);
Task.Run(ClientLoop);
}
public async void ClientLoop()
{
NetworkStream stream = client.GetStream();
byte[] msg = new byte[1 << 16];
while (client.Connected)
{
try
{
Array.Clear(msg, 0, msg.Length);
int len = stream.Read(msg, 0, msg.Length);
if (len > 0)
{
lastPacketTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
}
catch (Exception)
{
break;
}
await Task.Delay(10);
// 10 sec timeout
if (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - lastPacketTime > 10000)
break;
}
DisconnectProtocol();
}
public void DisconnectProtocol()
{
if (Server.Instance.Sessions.GetValueOrDefault(id) is null)
return;
c.Warn($"{id} disconnected");
client.Close();
Server.Instance.Sessions.Remove(id);
}
}
}

View File

@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AscNet.Common", "AscNet.Com
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AscNet.SDKServer", "AscNet.SDKServer\AscNet.SDKServer.csproj", "{B5040F93-BA7F-4E76-AF54-E3FAA857A5DA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AscNet.GameServer", "AscNet.GameServer\AscNet.GameServer.csproj", "{EB20C0CB-7CA1-459F-8410-7A27CC99F98C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -27,6 +29,10 @@ Global
{B5040F93-BA7F-4E76-AF54-E3FAA857A5DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5040F93-BA7F-4E76-AF54-E3FAA857A5DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5040F93-BA7F-4E76-AF54-E3FAA857A5DA}.Release|Any CPU.Build.0 = Release|Any CPU
{EB20C0CB-7CA1-459F-8410-7A27CC99F98C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB20C0CB-7CA1-459F-8410-7A27CC99F98C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB20C0CB-7CA1-459F-8410-7A27CC99F98C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB20C0CB-7CA1-459F-8410-7A27CC99F98C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AscNet.GameServer\AscNet.GameServer.csproj" />
<ProjectReference Include="..\AscNet.SDKServer\AscNet.SDKServer.csproj" />
</ItemGroup>
<ItemGroup>

File diff suppressed because one or more lines are too long