#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public override async Task HandleMessage(IProxiedMessageContext <AuthenticationClientPayload, AuthenticationServerPayload> context, AuthRealmListResponse payload) { if (Logger.IsInfoEnabled) { Logger.Info("Entered captures realm list packet handler."); } foreach (var realm in payload.Realms) { if (Logger.IsInfoEnabled) { Logger.Info($"Realm Listing: {realm} Address: {realm.Information.RealmAddress.RealmIP}:{realm.Information.RealmAddress.Port}"); } } //Rewrite the response to point to our proxy string realmString = payload.Realms.First().Information.RealmAddress.GetPropertyValue("RealmEndpointInformation") as string; string newRealmString = "127.0.0.1:8085"; //Also need to set t he new size payload.PayloadSize = (ushort)(payload.PayloadSize - (realmString.Length - newRealmString.Length)); if (Logger.IsInfoEnabled) { Logger.Info($"AddressString: {realmString}"); } //We should also modify the realm info RealmInfo realmInfo = RebuildRealmInfo(payload.Realms.First(), newRealmString); await context.ProxyConnection.SendMessage(new AuthRealmListResponse(payload.PayloadSize, new RealmInfo[1] { realmInfo })); }
/// <inheritdoc /> public async Task <bool> TryHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, NetworkIncomingMessage <GamePacketPayload> message) { NetworkOperationCode opCode = message.Payload.GetOperationCode(); if (Logger.IsInfoEnabled) { Logger.Info($"Client Sent: {opCode}:{opCode:X}"); } if (message.Payload is IPlayerMovementPayload <MovementInfo, MovementFlag, PackedGuid> payload) { //We should expect the payload to be a vanilla move info //Do NOT send guid. only server sends guid in 1.12.1 CustomMovePacketProxy_Vanilla proxy = new CustomMovePacketProxy_Vanilla(opCode, MoveInfoConverter.Convert(payload.MoveInfo) ?? throw new InvalidOperationException($"Failed to convert the move info.")); //We use a custom overload that allows low level byte writing to the proxy //This feature was LITERALLY implemented exactly for this payload //I added it to GladNet as a hack but it may see use elsewhere for performance reasons. await context.ProxyConnection.WriteAsync(Serializer.Serialize(proxy)); } else { throw new InvalidOperationException($"Recieved non-movement payload in movement handler. OpCode: {opCode} Type: {message.Payload.GetType().Name}"); } return(true); }
#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public override async Task HandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, GamePacketPayload payload) { if (Logger.IsWarnEnabled) { Logger.Warn($"Recieved unproxied Payload: {payload.GetOperationCode()}:{payload.GetType().Name}"); } if (payload is UnknownGamePayload) { return; } //Since we're connected to a vanilla realm we, at least for now, want to discard unknown opcode payloads if ((short)payload.GetOperationCode() > 0x41F || OpCodeBlackList.Contains(payload.GetOperationCode())) { if (Logger.IsWarnEnabled) { Logger.Warn($"Discarded by OpCode: {payload.GetOperationCode()} from server."); } return; } //Forward to the server await context.ProxyConnection.SendMessage(payload) .ConfigureAwait(false); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, SMSG_COMPRESSED_UPDATE_OBJECT_Payload_Vanilla payload) { UpdateBlockCollection collection = UpdateBlockConverter.Convert(payload.UpdateBlocks); //Once the blocks are rebuilt we can send the packet off on its way return(context.ProxyConnection.SendMessage(new SMSG_COMPRESSED_UPDATE_OBJECT_Payload(collection))); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, RealmSplitRequest payload) { //So vanilla servers don't do this packet //So we will respond with what Trinitycore sends which also just barley does handling on it //Don't use proxy connection because we want to send back to the client return(context.PayloadSendService.SendMessage(new RealmSplitResponse(payload.Unk))); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, CMSG_PLAYED_TIME_DTO_PROXY payload) { //TODO: Is this required? Does Mangos care if there is a byte here from 3.3.5? return(context.ProxyConnection.SendMessage(new CMSG_PLAYED_TIME_DTO_PROXY() { Data = Array.Empty <byte>() })); }
public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, TPacketToDiscardType payload) { if (Logger.IsDebugEnabled) { Logger.Debug($"Discarded: {payload.GetOperationCode()}"); } return(Task.CompletedTask); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, SessionAuthChallengeEvent_Vanilla payload) { //We need to transform this to the proper DTO. //The vanilla DTO is slightly different so we just construct a wotlk //version of it. //Console.WriteLine(payload.GetType().Name); //Console.WriteLine(payload.EventData.GetType().Name); return(context.ProxyConnection.SendMessage(new SessionAuthChallengeEvent(payload.EventData))); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, CMSG_UPDATE_ACCOUNT_DATA_PAYLOAD payload) { //So vanilla cmangos and mangos servers do not actually handle this packet //They just discard it. So we will send this packet, though it won't do anything, //and then we will respond to the client that the update was complete. //Forward and then respond to client, vanilla server won't respond. await context.ProxyConnection.SendMessage(payload); await context.PayloadSendService.SendMessage(new SMSG_UPDATE_ACCOUNT_DATA_COMPLETE_PAYLOAD(payload.DataType)); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> context, SharedWelcomePayload payload) { Console.WriteLine($"Recieved Welcome: {payload.CopyrightMessage}"); //Send first, or else client will not understand because it doesn't have encryption IV yet. await context.ProxyConnection.SendMessage(payload) .ConfigureAwait(false); CryptoInitializable.EncryptionInitializable.Initialize(payload.ClientVector); CryptoInitializable.DecryptionInitializable.Initialize(payload.ServerVector); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, CMSG_WORLD_STATE_UI_TIMER_UPDATE_DTO_PROXY payload) { if (Logger.IsDebugEnabled) { Logger.Debug($"Spoofing response to: {payload.GetOperationCode()}"); } //TODO: Is this time correct? //Vanilla 1.12.1 does not implement this packet. So we should sent current unix time stamp //in the spoofed response. return(context.PayloadSendService.SendMessage(new SMSG_WORLD_STATE_UI_TIMER_UPDATE_Payload((uint)DateTimeOffset.Now.ToUnixTimeSeconds()))); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, SMSG_INITIAL_SPELLS_Payload_Vanilla payload) { SMSG_INITIAL_SPELLS_Payload outputPayload = ConvertToOutputPayload(payload); await context.ProxyConnection.SendMessage(outputPayload); //TC sends this after the initial spells await context.ProxyConnection.SendMessage(new SMSG_SEND_UNLEARN_SPELLS_DTO_PROXY() { Data = 0.Reinterpret() }); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, CharacterListResponse payload) { if (Logger.IsInfoEnabled) { Logger.Info($"Captured CharListResponse packet. ProxyType: {context.ProxyConnection.GetType()} Going to Forward"); } //CharacterScreenCharacter character = payload.Characters.First(); //character.SetFieldValue($"<{nameof(CharacterScreenCharacter.Race)}>k__BackingField", (CharacterRace)12, Flags.AllMembers); return(context.ProxyConnection.SendMessageImmediately(payload, DeliveryMethod.ReliableOrdered)); }
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, CharacterListResponse_Vanilla payload) { if (Logger.IsInfoEnabled) { Logger.Info($"Captured CharListResponse_Vanilla packet. Transforming to wotlk version"); } //Transforms all the characters to their wotlk structure. CharacterScreenCharacter[] characters = payload.Characters .Select(CharacterConverter.Convert) .ToArray(); return(context.ProxyConnection.SendMessage(new CharacterListResponse(characters))); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <PSOBBGamePacketPayloadServer, PSOBBGamePacketPayloadClient> context, SharedDisconnectionRequestPayload payload) { //When we disconnect we must also clear the crypto data because they may reconnect and it's shared in the proxy CryptoInitializable.DecryptionInitializable.Uninitialize(); CryptoInitializable.EncryptionInitializable.Uninitialize(); //We should forward that we want the server to disconnect us, but we should disconnect the client right away and not wait. await context.ProxyConnection.SendMessage(payload) .ConfigureAwait(false); //Disconnects the client. await context.ConnectionService.DisconnectAsync(0) .ConfigureAwait(false); }
#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public async Task HandleMessage(IProxiedMessageContext <AuthenticationServerPayload, AuthenticationClientPayload> context, AuthenticationClientPayload payload) { if (Logger.IsWarnEnabled) { Logger.Warn($"Recieved unproxied Payload: {payload.GetType().Name} on {this.GetType().Name}"); } //TODO: We cannot implement the default behavior of the proxy because some information is lost when we recieve an unknown payload. //The information about the opcode is not exposed to the handler so we can just forward unknown messages. //Alternatives is to add a middleware/pipeline extension that forwards "uninteresting" opcodes without even //handling them. //Forward to the server await context.ProxyConnection.SendMessage(payload) .ConfigureAwait(false); }
/// <inheritdoc /> public async Task HandleMessage(IProxiedMessageContext <TOutgoingPayloadType, TBasePayloadType> context, TSpecificPayloadType payload) { //TODO: We can't log the opcode, should GladNet force users to expose it? //if(Logger.IsInfoEnabled) // Logger.Info($"Server Sent: {payload.GetOperationCode()}:{((int)payload.GetOperationCode()):X}"); try { await OnHandleMessage(context, payload) .ConfigureAwait(false); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Encountered Error in Handler: {GetType().Name} Exception: {e.Message} \n\n Stack: {e.StackTrace}"); } } }
/// <inheritdoc /> public async Task HandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, TSpecificPayloadType payload) { if (Logger.IsInfoEnabled) { Logger.Info($"Server Sent: {payload.GetOperationCode()}:{((int)payload.GetOperationCode()):X}"); } try { await OnHandleMessage(context, payload); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Encountered Error in Handler: {GetType().Name} Exception: {e.Message} \n\n Stack: {e.StackTrace}"); } } }
#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, SessionAuthProofRequest payload) { Logger.Info("About to require session key from client."); //Ok, so when the client sends this it is responding to an auth challenge event. //The response, whether we were successful or not, will have encrypted headers. //We must read the session key from the client now and then //we want to initialize our ingoing and outgoing encryption. Console.Write("Enter Warcraft ProcessId: "); string processId = Console.ReadLine(); byte[] sessionKey = ReadSessionKeyFromProcessMemory(processId); await context.ProxyConnection.SendMessage(new SessionAuthProofRequest_Vanilla(ClientBuild.Vanilla_1_12_1, payload.AccountName, payload.RandomSeedBytes, payload.SessionDigest)) .ConfigureAwait(false); //We should send the auth request before initializing encryption CryptoInitializer.Initialize(sessionKey); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> context, SharedConnectionRedirectPayload payload) { Logger.Info($"Redirecting to: {payload.EndpointAddress.ToString()}:{payload.EndpointerPort}"); //5001 is the port used when we are running the character server and login server starting from 5000 //so if we get a redirect to 5001 we should wire it to 12001 instead //This was the old design. We should ALWAYS connect to the same port. Just rewrite the IP to //go through 127.0.0.1 /*switch(payload.EndpointerPort) * { * case 5001: * payload = new SharedConnectionRedirectPayload(payload.EndpointAddress, 12001); * Logger.Info($"Switching Port to: {12001}"); * break; * case 5002: * payload = new SharedConnectionRedirectPayload(payload.EndpointAddress, 5278); * Logger.Info($"Switching Port to: {5278}"); * break; * case 5003: * payload = new SharedConnectionRedirectPayload(payload.EndpointAddress, 5279); * Logger.Info($"Switching Port to: {5279}"); * break; * }*/ payload = new SharedConnectionRedirectPayload("127.0.0.1", payload.EndpointerPort); //TODO: Handle port mapping //Just forward the redirect, also disconnect the client after uninitializing the crypto await context.ProxyConnection.SendMessageImmediately(payload) .ConfigureAwait(false); CryptoInitializable.EncryptionInitializable.Uninitialize(); CryptoInitializable.DecryptionInitializable.Uninitialize(); await context.ProxyConnection.DisconnectAsync(1) .ConfigureAwait(false); await context.ConnectionService.DisconnectAsync(1) .ConfigureAwait(false); }
#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, SessionAuthProofRequest payload) { Logger.Info("About to require session key from client."); //Ok, so when the client sends this it is responding to an auth challenge event. //The response, whether we were successful or not, will have encrypted headers. //We must read the session key from the client now and then //we want to initialize our ingoing and outgoing encryption. Console.Write("Enter Warcraft ProcessId: "); string processId = Console.ReadLine(); byte[] sessionKey = ReadSessionKeyFromProcessMemory(processId); //TODO: This isn't safe, because it is possible we recieve something before we initialize encryption. await context.ProxyConnection.SendMessageImmediately(payload, DeliveryMethod.ReliableOrdered) .ConfigureAwait(false); //We should send the auth request before initializing encryption CryptoInitializer.Initialize(sessionKey); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, TUnimplementedPacketPayloadType payload) { //When we recieve a packet we want to log the data BUT we always need to make sure we log the opcode appended to it so it can be deserialized Guid newGuid = Guid.NewGuid(); if (Logger.IsDebugEnabled) { Logger.Debug($"Logging: {OpCode} to file with GUID: {newGuid}"); } using (FileStream fs = File.Open(Path.Combine(PacketLogPath(), $"{BaseFileName}_{newGuid}"), FileMode.CreateNew)) { await fs.WriteAsync(OpCodeBytes, 0, OpCodeBytes.Length); await fs.WriteAsync(payload.Data, 0, payload.Data.Length); } if (ShouldForward) { await OnForwardingPayload(context, payload); } }
/// <inheritdoc /> public async Task HandleMessage(IProxiedMessageContext <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> context, PSOBBGamePacketPayloadServer payload) { //TODO: Kinda hacky to do it here, but keeping packets ordered this way. Mostly. using (await LockObj.LockAsync().ConfigureAwait(false)) { if (Logger.IsDebugEnabled) { Logger.Debug($"Recieved unhandled server payload Name: {payload.GetType().Name} with OpCode: {(GameNetworkOperationCode)payload.OperationCode} - {payload.OperationCode:X}"); } LogPayloadBytes(payload); await context.ProxyConnection.SendMessage(payload) .ConfigureAwait(false); } if (payload is IUnknownPayloadType u) { await PacketLogger.WritePacketAsync((GameNetworkOperationCode)payload.OperationCode, u, BinaryPacketWriter.PacketType.Server) .ConfigureAwait(false); } }
#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, AuthenticateSessionResponse payload) { if (Logger.IsInfoEnabled) { Logger.Info($"Auth Response Result: {payload.AuthenticationResult}"); } await context.ProxyConnection.SendMessageImmediately(payload, DeliveryMethod.ReliableOrdered) .ConfigureAwait(false); if (Logger.IsInfoEnabled) { Logger.Info($"Spoofing addon check information."); } //After the result is sent for game auth then the client will //expect that we send addon information otherwise addons won't work //We must send the //Make sure to send the client, not sever by accident await context.ProxyConnection.SendMessage(new SMSG_ADDON_INFO_Payload(Enumerable.Repeat(new AddonChecksumResult(0, false), 23).ToArray())) .ConfigureAwait(false); }
#pragma warning disable AsyncFixer01 // Unnecessary async/await usage /// <inheritdoc /> public virtual async Task HandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, GamePacketPayload payload) { if (Logger.IsWarnEnabled) { Logger.Warn($"Recieved unproxied Payload: {payload.GetType().Name} on {this.GetType().Name}"); } //TODO: We cannot implement the default behavior of the proxy because some information is lost when we recieve an unknown payload. //The information about the opcode is not exposed to the handler so we can just forward unknown messages. //Alternatives is to add a middleware/pipeline extension that forwards "uninteresting" opcodes without even //handling them. Console.ReadKey(); //TODO: Remove object update supression if (payload is UnknownGamePayload) //|| payload.GetOperationCode() == NetworkOperationCode.SMSG_COMPRESSED_UPDATE_OBJECT) { return; } //TODO: Check if it is default payload. We don't want to forward defaults/unknowns //Forward to the server await context.ProxyConnection.SendMessage(payload) .ConfigureAwait(false); }
/// <inheritdoc /> public override async Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, CharacterLoginRequest payload) { //TODO: May have to implement SendAccountDataTimes //Wotlk expects a lot of extra packets to be sent that 1.12.1 doesn't send //Forward the login request after these //3.3.5 TC sends in the following order for minimum login //Dungeon_Difficulty //Login_Verify_World //SMSG_MOTD //Guild stuff //Learned_Dance_Moves //SMSG_COMPRESSED_UPDATE_OBJECT //SMSG_COMPRESSED_UPDATE_OBJECT //CMSG_PLAYED_TIME await context.PayloadSendService.SendMessage(new SMSG_INSTANCE_DIFFICULTY_PAYLOAD()); await context.PayloadSendService.SendMessage(new SMSG_FEATURE_SYSTEM_STATUS_PAYLOAD(false)); //Do we need to send MOTD? I didn't test not sending. 1.12.1 doesn't have it. await context.PayloadSendService.SendMessage(new SMSG_MOTD_PAYLOAD(new string[1] { "Powered by Glader's FreecraftCore" })); await context.PayloadSendService.SendMessage(new SMSG_LEARNED_DANCE_MOVES_PAYLOAD()); await context.PayloadSendService.SendMessage(new SMSG_INSTANCE_DIFFICULTY_PAYLOAD()); //default difficulty //TODO: Renable maybe when we renable this packet //await context.PayloadSendService.SendMessage(new SMSG_CONTACT_LIST_PAYLOAD()); //send empty contact list //Forward the loginrequest and we will transform all the server payloads to the wotlk version as they come back in await context.ProxyConnection.SendMessage(payload); //TODO: Implement this better //We also need to send a special spell in 3.3.5 called LoginSpell //It is sent by the 3.3.5 server to confirm the login. await Task.Delay(5000) .ConfigureAwait(true); /*ServerToClient: SMSG_SPELL_GO (0x0132) Length: 36 ConnIdx: 0 EP: 127.0.0.1:59538 Time: 06/07/2018 21:59:58.785 Number: 55 * Caster GUID: Full: 0x00000004 Type: Player Low: 4 Name: Test * Caster Unit GUID: Full: 0x00000004 Type: Player Low: 4 Name: Test * Cast Count: 0 * Spell ID: 836 (836) * Cast Flags: 264449 (PendingCast, Unknown7, PredictedPower, Unknown16) * Time: 48644 * Hit Count: 1 * [0] Hit GUID: Full: 0x00000004 Type: Player Low: 4 Name: Test * Miss Count: 0 * Target Flags: 2 (Unit) * Target GUID: 0x0 * Rune Cooldown: 4253*/ Task.Factory.StartNew(async() => { int i = 0; while (true) { await context.PayloadSendService.SendMessage(new SMSG_TIME_SYNC_REQ_DTO_PROXY() { Data = i.Reinterpret() }); await Task.Delay(10000); i++; } }) .ConfigureAwait(false); //TODO: Time is off here, will it cause issues? //await context.PayloadSendService.SendMessage(new SMSG_SPELL_GO_Payload(new PackedGuid(payload.CharacterGuid.RawGuidValue), new PackedGuid(payload.CharacterGuid.RawGuidValue), 0, // 836, (SpellCastFlag)264449, 0, new ObjectGuid[1] {payload.CharacterGuid}, new SpellMissInfo[0], BuildLoginSpellTargetInfo(), 0, null, null, 0)); }
public abstract Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, TSpecificPayloadType payload);
public abstract Task OnHandleMessage(IProxiedMessageContext <TOutgoingPayloadType, TBasePayloadType> context, TSpecificPayloadType payload);
/// <inheritdoc /> public override Task OnHandleMessage(IProxiedMessageContext <GamePacketPayload, GamePacketPayload> context, TPayloadInputType payload) { //TODO: Should we handle null as a way to indicate don't send? return(context.ProxyConnection.SendMessage(ConvertToOutputPayload(payload))); }
/// <inheritdoc /> public abstract Task HandleMessage(IProxiedMessageContext <AuthenticationServerPayload, AuthenticationClientPayload> context, TSpecificPayloadType payload);