SCHALE.GameServer/SCHALE.GameServer/Utils/PcapUtils.cs

141 lines
5.1 KiB
C#

using Google.FlatBuffers;
using SCHALE.Common.NetworkProtocol;
using System.Text.Json.Nodes;
using System.Text;
using System.Text.Json;
using Newtonsoft.Json;
using Serilog;
using System.Reflection;
namespace SCHALE.GameServer.Utils
{
public static class PcapUtils
{
private static readonly string DefaultPcapFileName = "packets.json";
//private static readonly string CurrentPcapFileName = "";
private static List<RequestPacket> RequestPackets { get; } = null;
private static List<ResponsePacket> ResponsePackets { get; } = null;
static PcapUtils()
{
RequestPackets = new List<RequestPacket>();
ResponsePackets = new List<ResponsePacket>();
PcapUtils.Load(DefaultPcapFileName);
}
// gets all packets of that type
public static T[] GetPacketsFromPcap<T>(Protocol protocol, PacketType packetType) where T : BasePacket
{
if (packetType == PacketType.Request)
{
return RequestPackets.Where(x => x.Protocol == protocol).Select(x => x as T).ToArray();
}
else
{
return ResponsePackets.Where(x => x.Protocol == protocol).Select(x => x as T).ToArray();
}
}
// get a single packet, remember to change the sessionkey, accountId, etc..
public static T GetPacketFromPcap<T>(Protocol protocol, PacketType packetType) where T : BasePacket
{
return GetPacketsFromPcap<T>((Protocol)protocol, packetType).FirstOrDefault();
}
public static bool Load(string pcapFileName)
{
// clear first? not clearing can cause conflicts
RequestPackets.Clear();
ResponsePackets.Clear();
string PcapFilePath = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory), pcapFileName);
if (!Path.Exists(PcapFilePath))
{
Log.Error($"Pcap json file was not found at path {PcapFilePath}.");
return false;
}
var json = File.ReadAllText(PcapFilePath);
var jsonPackets = System.Text.Json.JsonSerializer.Deserialize<JsonArray>(json);
foreach (JsonNode packetNode in jsonPackets)
{
PacketType packetType = packetNode["type"].ToString() == "REQUEST" ? PacketType.Request : PacketType.Response;
JsonNode packetPayload = packetNode["payload"];
Protocol protocol = (Protocol?)packetPayload?["Protocol"]?.GetValue<int?>() ?? Protocol.None;
if (protocol == Protocol.None)
{
Log.Warning("Failed to read protocol from JsonNode, {Payload:j}", packetNode.ToString());
continue;
}
Type packetClassType;
object packet;
try
{
packetClassType = GetPacketTypeByProtocol(protocol, packetType);
packet = packetPayload.Deserialize(packetClassType);
} catch (Exception ex)
{
Log.Warning($"Failed to deserialize {packetNode["type"]} protocol {protocol} from JsonNode, payload: {packetPayload.ToString()}");
continue;
}
if (packetType == PacketType.Request)
{
RequestPackets.Add((RequestPacket)packet);
}
else
{
ResponsePackets.Add((ResponsePacket)packet);
}
Log.Information($"Loaded Pcap Type: {packetNode["type"]}, Protocol: {protocol}");
}
Log.Information($"Successfully Loaded Packets from: {PcapFilePath}!");
return true;
}
public static Type? GetPacketTypeByProtocol(Protocol protocol, PacketType packetType)
{
var assembly = Assembly.GetAssembly(typeof(BasePacket));
Type baseType = packetType == PacketType.Request ? typeof(RequestPacket) : typeof(ResponsePacket);
var packetTypeCandidates = assembly.GetTypes().Where(t => baseType.IsAssignableFrom(t) && !t.IsAbstract);
foreach (var candidate in packetTypeCandidates)
{
var protocolProperty = candidate.GetProperty("Protocol", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
if (protocolProperty != null && protocolProperty.PropertyType == typeof(Protocol))
{
var instance = Activator.CreateInstance(candidate);
if (instance != null)
{
var protocolValue = protocolProperty.GetValue(instance);
if (protocolValue != null && protocolValue.Equals(protocol))
{
return candidate;
}
}
}
}
return null;
}
}
public enum PacketType
{
Request,
Response,
}
}