diff --git a/Projects/Server/Exceptions/ExceptionExtensions.cs b/Projects/Server/Exceptions/ExceptionExtensions.cs new file mode 100644 index 000000000..48eafddd1 --- /dev/null +++ b/Projects/Server/Exceptions/ExceptionExtensions.cs @@ -0,0 +1,42 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ExceptionExtensions.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Diagnostics; +using System.Linq.Expressions; +using System.Reflection; + +namespace Server.Exceptions +{ + public static class ExceptionExtensions + { + public static Exception SetStackTrace(this Exception target, StackTrace stack) => _setStackTrace(target, stack); + + private static readonly Func _setStackTrace = _createStackTraceMethod(); + + private static Func _createStackTraceMethod() + { + ParameterExpression target = Expression.Parameter(typeof(Exception)); + ParameterExpression stack = Expression.Parameter(typeof(StackTrace)); + Type traceFormatType = typeof(StackTrace).GetNestedType("TraceFormat", BindingFlags.NonPublic); + MethodInfo toString = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { traceFormatType }, null); + object normalTraceFormat = Enum.GetValues(traceFormatType!).GetValue(0); + MethodCallExpression stackTraceString = Expression.Call(stack, toString!, Expression.Constant(normalTraceFormat, traceFormatType)); + FieldInfo stackTraceStringField = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance); + BinaryExpression assign = Expression.Assign(Expression.Field(target, stackTraceStringField!), stackTraceString); + return Expression.Lambda>(Expression.Block(assign, target), target, stack).Compile(); + } + } +} diff --git a/Projects/Server/Gumps/InvalidGumpResponseException.cs b/Projects/Server/Gumps/InvalidGumpResponseException.cs new file mode 100644 index 000000000..af2c11c6c --- /dev/null +++ b/Projects/Server/Gumps/InvalidGumpResponseException.cs @@ -0,0 +1,26 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: InvalidGumpResponseException.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; + +namespace Server.Gumps +{ + public class InvalidGumpResponseException : Exception + { + public InvalidGumpResponseException(string reason) : base(reason) + { + } + } +} diff --git a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs index 93bfbace6..50f664788 100644 --- a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs @@ -13,8 +13,10 @@ * along with this program. If not, see . * *************************************************************************/ +using System.Diagnostics; using Microsoft.Toolkit.HighPerformance.Extensions; using Server.Diagnostics; +using Server.Exceptions; using Server.Gumps; namespace Server.Network @@ -372,7 +374,12 @@ namespace Server.Network if (!buttonExists) { state.WriteConsole("Invalid gump response, disconnecting..."); - state.Disconnect("Invalid gump response."); + var exception = new InvalidGumpResponseException($"Button {buttonID} doesn't exist"); + exception.SetStackTrace(new StackTrace()); + NetState.TraceException(exception); + state.Mobile?.SendMessage("Invalid gump response."); + + // state.Disconnect("Invalid gump response."); return; } @@ -381,15 +388,20 @@ namespace Server.Network if (switchCount < 0 || switchCount > gump.m_Switches) { state.WriteConsole("Invalid gump response, disconnecting..."); - state.Disconnect("Invalid gump response."); + var exception = new InvalidGumpResponseException($"Bad switch count {switchCount}"); + exception.SetStackTrace(new StackTrace()); + NetState.TraceException(exception); + state.Mobile?.SendMessage("Invalid gump response."); + + // state.Disconnect("Invalid gump response."); return; } var switches = new int[switchCount]; - for (var j = 0; j < switches.Length; ++j) + for (var i = 0; i < switches.Length; ++i) { - switches[j] = reader.ReadInt32(); + switches[i] = reader.ReadInt32(); } var textCount = reader.ReadInt32(); @@ -397,13 +409,18 @@ namespace Server.Network if (textCount < 0 || textCount > gump.m_TextEntries) { state.WriteConsole("Invalid gump response, disconnecting..."); - state.Disconnect("Invalid gump response."); + var exception = new InvalidGumpResponseException($"Bad text entry count {textCount}"); + exception.SetStackTrace(new StackTrace()); + NetState.TraceException(exception); + state.Mobile?.SendMessage("Invalid gump response."); + + // state.Disconnect("Invalid gump response."); return; } var textEntries = new TextRelay[textCount]; - for (var j = 0; j < textEntries.Length; ++j) + for (var i = 0; i < textEntries.Length; ++i) { int entryID = reader.ReadUInt16(); int textLength = reader.ReadUInt16(); @@ -411,12 +428,17 @@ namespace Server.Network if (textLength > 239) { state.WriteConsole("Invalid gump response, disconnecting..."); - state.Disconnect("Invalid gump response."); + var exception = new InvalidGumpResponseException($"Text entry {i} is too long ({textLength})"); + exception.SetStackTrace(new StackTrace()); + NetState.TraceException(exception); + state.Mobile?.SendMessage("Invalid gump response."); + + // state.Disconnect("Invalid gump response."); return; } var text = reader.ReadBigUniSafe(textLength); - textEntries[j] = new TextRelay(entryID, text); + textEntries[i] = new TextRelay(entryID, text); } state.RemoveGump(gump);