Decompiled source of LCDirectLAN v1.1.3
BepInEx/plugins/LCDirectLAN.dll
Decompiled 7 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DnsClient; using DnsClient.Protocol; using GameNetcodeStuff; using HarmonyLib; using LCDirectLAN.Patches; using LCDirectLAN.Patches.ConfigurableLAN; using LCDirectLAN.Patches.CustomUsername; using LCDirectLAN.Patches.LatencyHUD; using LCDirectLAN.Patches.UnityNetworking; using LCDirectLAN.Utility; using Steamworks; using TMPro; using Unity.Collections; using Unity.Netcode; using Unity.Netcode.Transports.UTP; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("LCDirectLAN")] [assembly: AssemblyDescription("LCDirectLAN is a BepInEx plugin for Lethal Company that fixes and enhances LAN lobbies.")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCompany("Matthew Tirtawidjaja")] [assembly: AssemblyProduct("LCDirectLAN")] [assembly: AssemblyCopyright("Copyright © 2024 Matthew Tirtawidjaja")] [assembly: ComVisible(false)] [assembly: Guid("8551a54f-0c5c-48d0-acf2-1c91581cd69d")] [assembly: AssemblyFileVersion("1.1.3.10101")] [assembly: AssemblyInformationalVersion("1.1.3")] [assembly: AssemblyTrademark("Matthew Tirtawidjaja")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.1.3.10101")] namespace LCDirectLAN { [BepInPlugin("TIRTAGT.LCDirectLAN", "LCDirectLAN", "1.1.3")] public class LCDirectLan : BaseUnityPlugin { public const string PLUGIN_GUID = "TIRTAGT.LCDirectLAN"; public const string PLUGIN_NAME = "LCDirectLAN"; public const string PLUGIN_VERSION = "1.1.3"; public const string PLUGIN_ASSEMBLY_VERSION = "1.1.3.10101"; public const string PLUGIN_COMPILE_CONFIG = "Release"; private readonly Harmony HarmonyLib = new Harmony("TIRTAGT.LCDirectLAN"); private static LCDirectLan Instance; private static bool IsAlreadyAwake; private static ConfigFile config; public static bool IsOnLanMode; public LCDirectLan() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"TIRTAGT.LCDirectLAN is already loaded."); } else { Instance = this; } } private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Expected O, but got Unknown //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Expected O, but got Unknown //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Expected O, but got Unknown //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Expected O, but got Unknown //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Expected O, but got Unknown //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Expected O, but got Unknown //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Expected O, but got Unknown //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Expected O, but got Unknown //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Expected O, but got Unknown //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Expected O, but got Unknown //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Expected O, but got Unknown //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Expected O, but got Unknown if (IsAlreadyAwake) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"TIRTAGT.LCDirectLAN is already woken up."); return; } IsAlreadyAwake = true; config = new ConfigFile(Paths.ConfigPath + "/TIRTAGT.LCDirectLAN.cfg", true) { SaveOnConfigSet = false }; config.Bind<bool>("Join", "CreateExtraButton", true, new ConfigDescription("Add \"Direct LAN Join\" button to start menu, this will move other buttons on the UI and may not be compatible with other mods that also changes the start UI.\nDisabling this will override the game's default Join button function instead of creating a new button", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<string>("Join", "DefaultAddress", "127.0.0.1", new ConfigDescription("Default IP/Hostname, change-able in the game", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<ushort>("Join", "DefaultPort", (ushort)7777, new ConfigDescription("Default Port, change-able in the game", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Join", "RememberLastJoinSettings", false, new ConfigDescription("Overwrite the default join configuration values when changed in the game", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<byte>("Join", "HideRawJoinData", (byte)3, new ConfigDescription("Do not display or save the recently joined server data to avoid Server Leak, useful for streamers.\nThis config accepts a bitwise value\nExamples:\n0: Show anything (Disabled/No Hiding)\n1: Hide IP Address\n2. Hide Port Number\n3. Hide IP and Port\n4. Hide Hostname\n7. Hide all of them (IP,Port,Hostname)", (AcceptableValueBase)(object)new AcceptableValueList<byte>(new byte[6] { 0, 1, 2, 3, 4, 7 }), Array.Empty<object>())); config.Bind<bool>("Join", "SRVHost_PreferIPv6", false, new ConfigDescription("Prefer IPv6 over IPv4 for SRV Record host lookup when using DNS SRV Record to join", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Host", "ListenOnIPv6", false, new ConfigDescription("Should the game listen on IPv6 when hosting instead of IPv4 ?\nDual-Stack Listening is not supported due to the game Unity Transport version.", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<ushort>("Host", "DefaultPort", (ushort)7777, new ConfigDescription("Default Port for hosting, the default vanilla port is 7777", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Custom Username", "Enabled", false, new ConfigDescription("Enable CustomUsernamePatch ?\nThis patch requires both Server and Client(s) to work correctly, but having this enabled doesn't interfere with vanilla players (or players that didn't have this enabled).", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<string>("Custom Username", "HostDefaultUsername", "Lethal Hoster", new ConfigDescription("Default Username when Hosting a game", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Custom Username", "CreateHostUsernameInput", true, new ConfigDescription("Create input field for Host Username in the game's host configuration window, this will move other elements on the UI and may not be compatible with other mods that also changes the host UI.\nAdjust the offsets if necessary\n\nRequires the MergeDefaultUsername to be disabled in order to work correctly", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<Vector3>("Custom Username", "HostUsernameInput_Offset_Y", new Vector3(3f, -4f, -4f), new ConfigDescription("Y Offsets for multiple UI elements that were moved to make room for HostUsernameInput if it is enabled\n\nX value is the Header and the Remote/Local selection button\nY value is the confirm button\nZ value is the back button", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<string>("Custom Username", "JoinDefaultUsername", "Lethal Player", new ConfigDescription("Default Username when Joining a game\nChange-able in the game", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Custom Username", "MergeDefaultUsername", false, new ConfigDescription("Copy/Merge/Use JoinDefaultUsername as HostDefaultUsername too, breaks CreateHostUsernameInput functionality", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Unity Networking", "Enabled", false, new ConfigDescription("Enable UnityNetworkingPatch ?", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<short>("Unity Networking", "ConnectTimeout", (short)(-1), new ConfigDescription("Override the game connect/join timeout in seconds (any values lower than 1 will disable this)", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Latency HUD", "Enabled", true, new ConfigDescription("Enable LatencyHUDPatch ?", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Latency HUD", "DisableCustomLatencyRPC", false, new ConfigDescription("Disable LCDirectLAN's custom RPC and replace use UnityTransport's GetCurrentRtt() for measuring latency, additional warning feature will be disabled too", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Latency HUD", "HideHUDWhileHosting", true, new ConfigDescription("Hide the Latency HUD when hosting a game, since measuring latency to host (yourself) is not really useful", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Latency HUD", "RTTMeasurement", true, new ConfigDescription("Measure Round Trip Time (RTT) instead of one-way latency, which is a more accurate latency representation", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<bool>("Latency HUD", "DisplayWarningOnFailure", true, new ConfigDescription("Display an in-game warning when there is a problem with LatencyHUDPatch functionality", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<float>("Latency HUD", "Offset_X", 0f, new ConfigDescription("Adjust the X position of the Latency HUD\nHigher value moves the HUD to the right, lower value moves the HUD to the left", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<float>("Latency HUD", "Offset_Y", 0f, new ConfigDescription("Adjust the Y position of the Latency HUD\nHigher value moves the HUD to the top, lower value moves the HUD to the bottom", (AcceptableValueBase)null, Array.Empty<object>())); config.Bind<float>("Latency HUD", "TextSize", 13f, new ConfigDescription("Adjust font size of the Latency HUD (Minimum: 9)", (AcceptableValueBase)null, Array.Empty<object>())); config.Save(); PreInitSceneScriptPatch.SetLateInjector(InjectPatches); HarmonyLib.PatchAll(typeof(PreInitSceneScriptPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"LCDirectLAN is loaded"); } private void InjectPatches() { if (!IsOnLanMode) { ((BaseUnityPlugin)this).Logger.LogError((object)"LCDirectLAN should not be injected when game is started on Online (steam) mode"); return; } HarmonyLib.PatchAll(typeof(MenuManagerPatch)); if (GetConfig<bool>("Custom Username", "Enabled")) { HarmonyLib.PatchAll(typeof(PlayerControllerBPatch)); HarmonyLib.PatchAll(typeof(UsernameRPC)); } if (GetConfig<bool>("Unity Networking", "Enabled")) { HarmonyLib.PatchAll(typeof(UnityTransportPatch)); } if (GetConfig<bool>("Latency HUD", "Enabled")) { HarmonyLib.PatchAll(typeof(HUDManagerPatch)); HarmonyLib.PatchAll(typeof(LatencyRPC)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"LCDirectLAN patches are injected"); } public static void Log(LogLevel level, object data) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ((BaseUnityPlugin)Instance).Logger.Log(level, data); } public static T GetConfig<T>(string key) { return GetConfig<T>("Main", key); } public static T GetConfig<T>(string section, string key) { if (config == null) { return default(T); } ConfigEntry<T> val = default(ConfigEntry<T>); if (config.TryGetEntry<T>(section, key, ref val)) { return val.Value; } Log((LogLevel)4, "Cannot get config key " + key + ", no such key on " + section); return default(T); } public static bool SetConfig<T>(string key, T value) { return SetConfig(key, value); } public static bool SetConfig<T>(string section, string key, T value) { if (config == null) { return false; } ConfigEntry<T> val = default(ConfigEntry<T>); if (!config.TryGetEntry<T>(section, key, ref val)) { Log((LogLevel)4, $"Cannot set config key {key} to {value}, no such key on {section}"); return false; } val.Value = value; return true; } public static void SaveConfig() { if (config != null) { config.Save(); } } } } namespace LCDirectLAN.Utility { internal class allPlayerScripts { public static int GetActualPlayerIndex(ulong ClientID) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return -1; } for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++) { if (StartOfRound.Instance.allPlayerScripts[i].actualClientId == ClientID) { return i; } } return -1; } public static string GetPlayerUsername(int PlayerID) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return null; } if (PlayerID < 0 || PlayerID >= StartOfRound.Instance.allPlayerScripts.Length) { return null; } return StartOfRound.Instance.allPlayerScripts[PlayerID].playerUsername; } } internal class GameObjectManager { public static bool EnsureGameObjectExist(string path, out GameObject obj) { if (!IsExist(path, out obj)) { LCDirectLan.Log((LogLevel)2, "Cannot find " + path + " !"); return false; } return true; } public static bool IsExist(string name, out GameObject obj) { obj = GameObject.Find(name); return (Object)(object)obj != (Object)null; } public static bool IsExist(string name) { return (Object)(object)GameObject.Find(name) != (Object)null; } public static GameObject GetGameObject(string name) { return GameObject.Find(name); } public static bool DeleteGameObject(string path) { if (!IsExist(path, out var obj)) { return false; } Object.Destroy((Object)(object)obj); return true; } public static bool DeleteGameObject(GameObject obj) { if ((Object)(object)obj == (Object)null) { return false; } Object.Destroy((Object)(object)obj); return true; } } internal class ResolveDNS { private static readonly Regex HostnameRuleMatch = new Regex("^(((([a-z0-9])|([a-z0-9](-|_)[a-z]))+\\.)+(([a-z0-9])|([a-z0-9](-|_)[a-z0-9]))+)$"); public static string ResolveARecord(string record_name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) string result = string.Empty; LookupClient val = new LookupClient(); IDnsQueryResponse val2 = null; try { val2 = val.Query(record_name, (QueryType)1, (QueryClass)1); } catch (SocketException ex) { LCDirectLan.Log((LogLevel)2, "Failed to resolve A Record: " + ex.Message); } if (val2 == null) { return result; } if (val2.HasError) { return result; } for (int i = 0; i < val2.Answers.Count; i++) { if (val2.Answers[i] != null && val2.Answers[i] is ARecord) { result = ((AddressRecord)(ARecord)val2.Answers[i]).Address.ToString(); break; } } return result; } public static string ResolveAAAARecord(string record_name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) string result = string.Empty; LookupClient val = new LookupClient(); IDnsQueryResponse val2 = null; try { val2 = val.Query(record_name, (QueryType)28, (QueryClass)1); } catch (SocketException ex) { LCDirectLan.Log((LogLevel)2, "Failed to resolve AAAA Record: " + ex.Message); } if (val2 == null) { return result; } if (val2.HasError) { return result; } for (int i = 0; i < val2.Answers.Count; i++) { if (val2.Answers[i] != null && val2.Answers[i] is AaaaRecord) { result = ((AddressRecord)(AaaaRecord)val2.Answers[i]).Address.ToString(); break; } } return result; } public static string ResolveTXTRecord(string record_name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) string result = string.Empty; LookupClient val = new LookupClient(); IDnsQueryResponse val2 = null; try { val2 = val.Query(record_name, (QueryType)16, (QueryClass)1); } catch (SocketException ex) { LCDirectLan.Log((LogLevel)2, "Failed to resolve TXT Record: " + ex.Message); } if (val2 == null) { return result; } if (val2.HasError) { return result; } for (int i = 0; i < val2.Answers.Count; i++) { if (val2.Answers[i] == null || !(val2.Answers[i] is TxtRecord)) { continue; } using (IEnumerator<string> enumerator = ((TxtRecord)val2.Answers[i]).EscapedText.GetEnumerator()) { if (enumerator.MoveNext()) { result = enumerator.Current; } } break; } return result; } public static (string, ushort) ResolveSRVRecord(string record_name) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown (string, ushort) result = (string.Empty, 0); LookupClient val = new LookupClient(); IDnsQueryResponse val2 = null; try { val2 = val.Query(record_name, (QueryType)33, (QueryClass)1); } catch (SocketException ex) { LCDirectLan.Log((LogLevel)2, "Failed to resolve SRV Record: " + ex.Message); return result; } if (val2 == null) { return result; } if (val2.HasError) { return result; } for (int i = 0; i < val2.Answers.Count; i++) { if (val2.Answers[i] == null || !(val2.Answers[i] is SrvRecord)) { continue; } SrvRecord val3 = (SrvRecord)val2.Answers[i]; if (LCDirectLan.GetConfig<bool>("Join", "SRVHost_PreferIPv6")) { result.Item1 = ResolveAAAARecord(val3.Target.Value); if (string.IsNullOrEmpty(result.Item1)) { result.Item1 = ResolveARecord(val3.Target.Value); LCDirectLan.Log((LogLevel)16, "SRV Host is looked up using A Record"); } else { LCDirectLan.Log((LogLevel)16, "SRV Host is looked up using AAAA Record"); } result.Item2 = val3.Port; } else { result.Item1 = ResolveARecord(val3.Target.Value); if (string.IsNullOrEmpty(result.Item1)) { result.Item1 = ResolveAAAARecord(val3.Target.Value); LCDirectLan.Log((LogLevel)16, "SRV Host is looked up using AAAA Record"); } else { LCDirectLan.Log((LogLevel)16, "SRV Host is looked up using A Record"); } result.Item2 = val3.Port; } break; } return result; } public static bool IsValidIPv4(string ip) { if (IPAddress.TryParse(ip, out IPAddress address)) { return address.AddressFamily == AddressFamily.InterNetwork; } return false; } public static bool IsValidIPv6(string ip) { if (IPAddress.TryParse(ip, out IPAddress address)) { return address.AddressFamily == AddressFamily.InterNetworkV6; } return false; } public static AddressFamily CheckIPType(string ip) { if (IsValidIPv4(ip)) { return AddressFamily.InterNetwork; } if (IsValidIPv6(ip)) { return AddressFamily.InterNetworkV6; } return AddressFamily.Unknown; } public static bool IsOnHostnameFormat(string hostname) { if (hostname == "localhost") { return true; } if (CheckIPType(hostname) != AddressFamily.Unknown) { return false; } return HostnameRuleMatch.IsMatch(hostname); } } } namespace LCDirectLAN.Patches { [HarmonyPatch(typeof(PreInitSceneScript))] internal class PreInitSceneScriptPatch { private static Action LateInjector; private static bool HasAlreadyLaunched; [HarmonyPatch("ChooseLaunchOption")] [HarmonyPostfix] [HarmonyPriority(100)] public static void Postfix_ChooseLaunchOption(PreInitSceneScript __instance, bool online) { if (!HasAlreadyLaunched) { HasAlreadyLaunched = true; LCDirectLan.IsOnLanMode = !online; if (!LCDirectLan.IsOnLanMode) { LCDirectLan.Log((LogLevel)4, "LCDirectLAN is disabled when game is started on Online (steam) mode"); return; } LCDirectLan.Log((LogLevel)16, "LCDirectLAN is enabled"); LateInjector?.BeginInvoke(null, null); LateInjector = null; } } public static void SetLateInjector(Action action) { LateInjector = action; } } } namespace LCDirectLAN.Patches.UnityNetworking { [HarmonyPatch(typeof(NetworkManager))] internal class UnityTransportPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] [HarmonyPriority(100)] public static void Postfix_Awake(NetworkManager __instance) { UnityTransport component = ((Component)__instance).GetComponent<UnityTransport>(); if ((Object)(object)component == (Object)null) { LCDirectLan.Log((LogLevel)2, "Cannot modify ConnectTimeout, cannot find NetworkManager !"); return; } short config = LCDirectLan.GetConfig<short>("Unity Networking", "ConnectTimeout"); if (config >= 1) { component.MaxConnectAttempts = config; LCDirectLan.Log((LogLevel)16, $"Modified UnityTransport.MaxConnectAttempts to {config}"); } } } } namespace LCDirectLAN.Patches.LatencyHUD { [HarmonyPatch(typeof(HUDManager))] internal class HUDManagerPatch { private static GameObject LatencyHUD; private static TextMeshProUGUI LatencyHUD_TMP; private static ulong LatencyValue; private static bool UpdateLock; [HarmonyPatch("Awake")] [HarmonyPostfix] [HarmonyPriority(100)] public static void Postfix_Awake(HUDManager __instance) { LCDirectLan.Log((LogLevel)32, "HUDManager.Postfix_Awake()"); GameObject val = GameObject.Find("Systems/UI/Canvas/IngamePlayerHUD"); if ((Object)(object)val == (Object)null) { LCDirectLan.Log((LogLevel)2, "Cannot find IngamePlayerHUD GameObject !"); return; } GameObject val2 = GameObject.Find("Systems/UI/Canvas/IngamePlayerHUD/LCDirectLAN_LatencyHUD"); if ((Object)(object)val2 != (Object)null) { LCDirectLan.Log((LogLevel)32, "LatencyHUD already exists !"); LatencyHUD = val2; } else if ((Object)(object)NetworkManager.Singleton == (Object)null) { LCDirectLan.Log((LogLevel)2, "NetworkManager.Singleton is null !"); } else if (LCDirectLan.GetConfig<bool>("Latency HUD", "HideHUDWhileHosting") && NetworkManager.Singleton.IsServer) { LCDirectLan.Log((LogLevel)32, "Latency HUD is disabled while hosting !"); } else { CreateLatencyHUD(val); } } private static void CreateLatencyHUD(GameObject Container) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("Systems/UI/Canvas/IngamePlayerHUD/TopLeftCorner/WeightUI/Weight"); if ((Object)(object)val == (Object)null) { LCDirectLan.Log((LogLevel)2, "Cannot find Weight GameObject !"); return; } LatencyHUD = Object.Instantiate<GameObject>(val, Container.transform); float config = LCDirectLan.GetConfig<float>("Latency HUD", "Offset_X"); float config2 = LCDirectLan.GetConfig<float>("Latency HUD", "Offset_Y"); ((Object)LatencyHUD).name = "LCDirectLAN_LatencyHUD"; LatencyHUD.transform.SetLocalPositionAndRotation(new Vector3(-380f + config, 229f + config2, 0f), LatencyHUD.transform.rotation); LatencyHUD_TMP = LatencyHUD.GetComponent<TextMeshProUGUI>(); ((TMP_Text)LatencyHUD_TMP).fontSizeMin = 9f; ((TMP_Text)LatencyHUD_TMP).fontSize = LCDirectLan.GetConfig<float>("Latency HUD", "TextSize"); if (((TMP_Text)LatencyHUD_TMP).fontSize < ((TMP_Text)LatencyHUD_TMP).fontSizeMin) { ((TMP_Text)LatencyHUD_TMP).fontSize = ((TMP_Text)LatencyHUD_TMP).fontSizeMin; } ((TMP_Text)LatencyHUD_TMP).text = "Ping : [Calculating] ms"; ((TMP_Text)LatencyHUD_TMP).maxVisibleCharacters = 23; } [HarmonyPatch("Update")] [HarmonyPostfix] [HarmonyPriority(100)] public static void Postfix_Update() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (UpdateLock) { return; } UpdateLock = true; if (!((Object)(object)LatencyHUD_TMP == (Object)null)) { if (LatencyValue > 600) { ((Graphic)LatencyHUD_TMP).color = new Color(1f, 0f, 0f, 1f); } else if (LatencyValue > 300) { ((Graphic)LatencyHUD_TMP).color = new Color(0.9528f, 0.3941f, 0f, 1f); } else { ((Graphic)LatencyHUD_TMP).color = new Color(0f, 1f, 0f, 1f); } ((TMP_Text)LatencyHUD_TMP).text = $"Ping : {LatencyValue} ms"; } } public static void UpdateLatencyHUD(ushort latency) { if (!((Object)(object)LatencyHUD_TMP == (Object)null)) { LatencyValue = latency; UpdateLock = false; } } public static void DisplayHUDWarning(string message) { if (LCDirectLan.GetConfig<bool>("Latency HUD", "DisplayWarningOnFailure")) { HUDManager.Instance.DisplayTip("LCDirectLAN - Latency HUD", message, false, false, "LC_Tip1"); } } public static void DestroyLatencyHUD() { if ((Object)(object)LatencyHUD != (Object)null) { LatencyHUD.SetActive(false); LatencyHUD_TMP = null; Object.Destroy((Object)(object)LatencyHUD); LatencyHUD = null; } } } internal class LatencyRPC : NetworkBehaviour { private static bool IsWaitingPingCallback = false; private static Coroutine LatencyTrackerCoroutine; private static bool UseCustomLatencyRPC = true; private static UnityTransport UnityTransportObject; [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] [HarmonyPriority(100)] public static void Postfix_ConnectClientToPlayerObject(PlayerControllerB __instance) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown LCDirectLan.Log((LogLevel)32, "LatencyRPC.Postfix_ConnectClientToPlayerObject()"); if ((Object)(object)((NetworkBehaviour)__instance).NetworkManager == (Object)null || !((NetworkBehaviour)__instance).NetworkManager.IsListening || !((NetworkBehaviour)__instance).IsOwner) { return; } UseCustomLatencyRPC = !LCDirectLan.GetConfig<bool>("Latency HUD", "DisableCustomLatencyRPC"); if (UseCustomLatencyRPC) { LCDirectLan.Log((LogLevel)32, "Using Custom Latency RPC"); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LCDirectLAN_ClientLatencyRequestCallback_ToClientRpc", new HandleNamedMessageDelegate(ClientLatencyRequestCallback)); LCDirectLan.Log((LogLevel)32, "Listening _ClientLatencyRequestCallback_ToClientRpc"); if (!((NetworkBehaviour)__instance).NetworkManager.IsServer) { StartTrackingLatency((MonoBehaviour)(object)__instance); return; } NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LCDirectLAN_ClientLatencyRequest_ToServerRpc", new HandleNamedMessageDelegate(ClientLatencyRequest)); LCDirectLan.Log((LogLevel)32, "Listening _ClientLatencyRequest_ToServerRpc()"); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LCDirectLAN_ServerLatencyRequestCallback_ToServerRpc", new HandleNamedMessageDelegate(ServerLatencyRequestCallback)); LCDirectLan.Log((LogLevel)32, "Listening _ServerLatencyRequestCallback_ToServerRpc()"); if (LCDirectLan.GetConfig<bool>("Latency HUD", "HideHUDWhileHosting") && NetworkManager.Singleton.IsServer) { LCDirectLan.Log((LogLevel)32, "Not tracking latency as a server !"); } else { StartTrackingLatency((MonoBehaviour)(object)__instance); } } else { LCDirectLan.Log((LogLevel)32, "Using UnityTransport's RTT"); UnityTransportObject = GameObject.Find("NetworkManager").GetComponent<UnityTransport>(); StartTrackingLatency((MonoBehaviour)(object)__instance); } } [HarmonyPatch(typeof(PlayerControllerB), "OnDestroy")] [HarmonyPrefix] [HarmonyPriority(100)] public static void Prefix_OnDestroy(PlayerControllerB __instance) { if (!((NetworkBehaviour)__instance).IsOwner) { return; } LCDirectLan.Log((LogLevel)32, "LatencyRPC.Prefix_OnDestroy()"); StopTrackingLatency((MonoBehaviour)(object)__instance); UnityTransportObject = null; if (!((Object)(object)((NetworkBehaviour)__instance).NetworkManager == (Object)null) && ((NetworkBehaviour)__instance).NetworkManager.IsListening && !((Object)(object)NetworkManager.Singleton == (Object)null)) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LCDirectLAN_ClientLatencyRequestCallback_ToClientRpc"); if (((NetworkBehaviour)__instance).NetworkManager.IsServer) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LCDirectLAN_ClientLatencyRequest_ToServerRpc"); NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LCDirectLAN_ServerLatencyRequestCallback_ToServerRpc"); } } } public static void StartTrackingLatency(MonoBehaviour __instance) { LCDirectLan.Log((LogLevel)32, "LatencyRPC.StartTrackingLatency()"); if (LatencyTrackerCoroutine != null) { LCDirectLan.Log((LogLevel)4, "LatencyTrackerCoroutine is already running !"); } else { LatencyTrackerCoroutine = __instance.StartCoroutine(LatencyTracker_Coroutine()); } } private static IEnumerator LatencyTracker_Coroutine() { if (!LCDirectLan.IsOnLanMode) { yield break; } float SecondsSinceIsWaitingPing = 0f; float TargetPollingInterval = 3f; float ServerWarnTimeout = 4.5f; bool RetryPing = false; bool HasSentHUDWarning = false; bool KeepRunning = true; bool IsServerSupportLatencyRPC = false; while (KeepRunning) { if (!IsWaitingPingCallback || RetryPing) { if (!UseCustomLatencyRPC) { IsWaitingPingCallback = false; if (!FetchUnityLatency(ref SecondsSinceIsWaitingPing)) { HUDManagerPatch.DestroyLatencyHUD(); break; } } else { if ((Object)(object)NetworkManager.Singleton == (Object)null) { LCDirectLan.Log((LogLevel)4, "NetworkManager.Singleton is null, cannot send LatencyRPC ping request !"); HUDManagerPatch.DisplayHUDWarning("Unable to find NetworkManager for LatencyRPC ping request"); UnityTransportObject = GameObject.Find("NetworkManager").GetComponent<UnityTransport>(); UseCustomLatencyRPC = false; RetryPing = true; continue; } SendCustomLatencyRequest(ref SecondsSinceIsWaitingPing, ref IsWaitingPingCallback); } } yield return (object)new WaitForSeconds(0.2f); SecondsSinceIsWaitingPing += 0.2f; if (!IsWaitingPingCallback) { if (UseCustomLatencyRPC) { IsServerSupportLatencyRPC = true; } RetryPing = false; HasSentHUDWarning = false; if (SecondsSinceIsWaitingPing < TargetPollingInterval) { yield return (object)new WaitForSeconds(TargetPollingInterval - SecondsSinceIsWaitingPing); } } else { if (!(SecondsSinceIsWaitingPing >= ServerWarnTimeout)) { continue; } if (UseCustomLatencyRPC && !IsServerSupportLatencyRPC) { LCDirectLan.Log((LogLevel)4, "Server did not respond to first ping request, server may not support LatencyRPC !"); HUDManagerPatch.DisplayHUDWarning("Server did not support LatencyRPC, switching to UnityTransport..."); UnityTransportObject = GameObject.Find("NetworkManager").GetComponent<UnityTransport>(); UseCustomLatencyRPC = false; RetryPing = true; continue; } LCDirectLan.Log((LogLevel)4, "Server have not responded to our last ping request !"); HUDManagerPatch.UpdateLatencyHUD((ushort)(SecondsSinceIsWaitingPing * 1000f)); if (!HasSentHUDWarning) { HUDManagerPatch.DisplayHUDWarning("Server stopped responding to ping, slow server or connection lost ?"); HasSentHUDWarning = true; } yield return (object)new WaitForSeconds(1.5f); SecondsSinceIsWaitingPing += 1.5f; RetryPing = true; } } } private static bool FetchUnityLatency(ref float SecondsSinceIsWaitingPing) { if ((Object)(object)UnityTransportObject == (Object)null) { LCDirectLan.Log((LogLevel)2, "UnityTransportObject is null, Latency Patch will be disabled !"); HUDManagerPatch.DisplayHUDWarning("Unable to find UnityTransport, Latency Patch will be disabled."); return false; } SecondsSinceIsWaitingPing = 0f; ulong num = ((NetworkTransport)UnityTransportObject).GetCurrentRtt(0uL); if (LCDirectLan.GetConfig<bool>("Latency HUD", "RTTMeasurement")) { LCDirectLan.Log((LogLevel)32, $"Our RTT Latency (Unity): {num}ms"); } else { num /= 2; LCDirectLan.Log((LogLevel)32, $"Our One-Way Latency (Unity): {num}ms"); } HUDManagerPatch.UpdateLatencyHUD((ushort)num); return true; } private static void SendCustomLatencyRequest(ref float SecondsSinceIsWaitingPing, ref bool IsWaitingPingCallback) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); long currentEpochMilis = GetCurrentEpochMilis(); ((FastBufferWriter)(ref val)).WriteValue<long>(ref currentEpochMilis, default(ForPrimitives)); if (!IsWaitingPingCallback) { IsWaitingPingCallback = true; SecondsSinceIsWaitingPing = 0f; } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LCDirectLAN_ClientLatencyRequest_ToServerRpc", 0uL, val, (NetworkDelivery)0); } public static void StopTrackingLatency(MonoBehaviour __instance) { LCDirectLan.Log((LogLevel)32, "LatencyRPC.StopTrackingLatency()"); if (LatencyTrackerCoroutine != null) { if ((Object)(object)__instance == (Object)null) { LCDirectLan.Log((LogLevel)4, "Cannot stop LatencyRPC.LatencyTrackerCoroutine, MonoBehaviour instance is null !"); LatencyTrackerCoroutine = null; } else { __instance.StopCoroutine(LatencyTrackerCoroutine); LatencyTrackerCoroutine = null; } } } [ServerRpc] public static void ClientLatencyRequest(ulong ClientID, FastBufferReader reader) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) long num = default(long); ((FastBufferReader)(ref reader)).ReadValue<long>(ref num, default(ForPrimitives)); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue<long>(ref num, default(ForPrimitives)); long currentEpochMilis = GetCurrentEpochMilis(); ((FastBufferWriter)(ref val)).WriteValue<long>(ref currentEpochMilis, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LCDirectLAN_ClientLatencyRequestCallback_ToClientRpc", ClientID, val, (NetworkDelivery)0); if (ClientID != 0L) { LCDirectLan.Log((LogLevel)32, $"Replied to ClientID {ClientID}'s ping request !"); } } [ClientRpc] public static void ClientLatencyRequestCallback(ulong ClientID, FastBufferReader reader) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) long currentEpochMilis = GetCurrentEpochMilis(); long num = default(long); ((FastBufferReader)(ref reader)).ReadValue<long>(ref num, default(ForPrimitives)); long num2 = default(long); ((FastBufferReader)(ref reader)).ReadValue<long>(ref num2, default(ForPrimitives)); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue<long>(ref num2, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LCDirectLAN_ServerLatencyRequestCallback_ToServerRpc", 0uL, val, (NetworkDelivery)0); ushort num3 = (ushort)(currentEpochMilis - num); if (LCDirectLan.GetConfig<bool>("Latency HUD", "RTTMeasurement")) { LCDirectLan.Log((LogLevel)32, $"Our RTT Latency: {num3}ms"); } else { num3 /= 2; LCDirectLan.Log((LogLevel)32, $"Our One-Way Latency: {num3}ms"); } HUDManagerPatch.UpdateLatencyHUD(num3); IsWaitingPingCallback = false; } [ServerRpc] public static void ServerLatencyRequestCallback(ulong ClientID, FastBufferReader reader) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) long currentEpochMilis = GetCurrentEpochMilis(); long num = default(long); ((FastBufferReader)(ref reader)).ReadValue<long>(ref num, default(ForPrimitives)); int actualPlayerIndex = allPlayerScripts.GetActualPlayerIndex(ClientID); if (actualPlayerIndex != 0) { short num2 = (short)(currentEpochMilis - num); string playerUsername = allPlayerScripts.GetPlayerUsername(actualPlayerIndex); if (playerUsername == $"Player #{actualPlayerIndex}") { LCDirectLan.Log((LogLevel)32, $"Player #{actualPlayerIndex}'s RTT Latency: {num2}ms, Estimated One-Way Latency: {num2 / 2}ms"); } else { LCDirectLan.Log((LogLevel)32, $"{playerUsername}'s RTT Latency: {num2}ms, Estimated One-Way Latency: {num2 / 2}ms"); } } } private static long GetCurrentEpochMilis() { return DateTimeOffset.Now.ToUnixTimeMilliseconds(); } } } namespace LCDirectLAN.Patches.CustomUsername { [HarmonyPatch(typeof(PlayerControllerB))] internal class PlayerControllerBPatch { [HarmonyPatch("ConnectClientToPlayerObject")] [HarmonyPrefix] [HarmonyPriority(100)] public static void Prefix_ConnectClientToPlayerObject(PlayerControllerB __instance) { LCDirectLan.Log((LogLevel)32, $"Prefix_ConnectClientToPlayerObject({__instance.actualClientId},{((NetworkBehaviour)__instance).IsServer},{((NetworkBehaviour)__instance).IsOwner},{((NetworkBehaviour)__instance).IsClient})"); if (!((NetworkBehaviour)__instance).IsOwner) { LCDirectLan.Log((LogLevel)32, $"Skipped changing username on ClientID {__instance.actualClientId}, because it isn't the local player."); } else if (((NetworkBehaviour)__instance).IsServer) { if (LCDirectLan.GetConfig<bool>("Custom Username", "MergeDefaultUsername")) { __instance.playerUsername = LCDirectLan.GetConfig<string>("Custom Username", "JoinDefaultUsername"); } else { __instance.playerUsername = LCDirectLan.GetConfig<string>("Custom Username", "HostDefaultUsername"); } LCDirectLan.Log((LogLevel)32, "ConnectClientToPlayerObject() " + __instance.playerUsername + " (HOSTING)"); UsernameRPC.SendInformationToServerRpc(__instance.playerUsername); } else { __instance.playerUsername = LCDirectLan.GetConfig<string>("Custom Username", "JoinDefaultUsername"); LCDirectLan.Log((LogLevel)32, "ConnectClientToPlayerObject() " + __instance.playerUsername + " (JOINING)"); UsernameRPC.SendInformationToServerRpc(__instance.playerUsername); LCDirectLan.Log((LogLevel)32, "Successfully executed SendInformationToServerRpc('" + __instance.playerUsername + "')"); } } } internal class StartOfRoundPatch { public static void LatePatch_PlayerNameOnMapScreen() { if (!((Object)(object)StartOfRound.Instance.mapScreen.targetedPlayer == (Object)null)) { ((TMP_Text)StartOfRound.Instance.mapScreenPlayerName).text = "MONITORING: " + StartOfRound.Instance.mapScreen.targetedPlayer.playerUsername; } } } internal class UsernameRPC : NetworkBehaviour { private static bool[] PlayerSyncStatus = new bool[0]; private static byte PlayerSyncBroadcastID = 0; private static readonly byte PlayerSyncWaitTimeout = 30; private static bool IsBroadcastingPlayerUsernames = false; [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPrefix] [HarmonyPriority(600)] public static void Prefix_ConnectClientToPlayerObject(PlayerControllerB __instance) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown LCDirectLan.Log((LogLevel)32, $"UsernameRPC.Prefix_ConnectClientToPlayerObject({((NetworkBehaviour)__instance).NetworkManager.LocalClientId})"); if ((Object)(object)((NetworkBehaviour)__instance).NetworkManager == (Object)null || !((NetworkBehaviour)__instance).NetworkManager.IsListening || !((NetworkBehaviour)__instance).IsOwner) { return; } NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LCDirectLAN_GlobalUsernameRefresh_ToClientRpc", new HandleNamedMessageDelegate(GlobalUsernameRefresh_ToClientRpc)); LCDirectLan.Log((LogLevel)32, "Listening _GlobalUsernameRefresh_ToClientRpc()"); if (((NetworkBehaviour)__instance).NetworkManager.IsServer) { PlayerSyncStatus = new bool[StartOfRound.Instance.allPlayerScripts.Length]; for (int i = 0; i < PlayerSyncStatus.Length; i++) { PlayerSyncStatus[i] = false; } NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LCDirectLAN_ClientUsernameChanged_ToServerRpc", new HandleNamedMessageDelegate(ClientUsernameChanged_ToServerRpc)); LCDirectLan.Log((LogLevel)32, "Listening _ClientUsernameChanged_ToServerRpc()"); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LCDirectLAN_ClientReceivedUsernameRefresh_ToServerRpc", new HandleNamedMessageDelegate(ClientReceivedUsernameRefresh_ToServerRpc)); LCDirectLan.Log((LogLevel)32, "Listening _ClientReceivedUsernameRefresh_ToServerRpc()"); } } [ServerRpc] public static void ClientUsernameChanged_ToServerRpc(ulong ClientID, FastBufferReader reader) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer) { return; } int actualPlayerIndex = allPlayerScripts.GetActualPlayerIndex(ClientID); LCDirectLan.Log((LogLevel)32, $"SERVER: Received username changed event from ClientID {ClientID}, PlayerID {actualPlayerIndex} !"); if (((FastBufferReader)(ref reader)).TryBeginRead(1)) { byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValue<byte>(ref b, default(ForPrimitives)); if (b == 0) { LCDirectLan.Log((LogLevel)4, "SERVER: Client sent a empty username change request, IGNORED !"); return; } if (!((FastBufferReader)(ref reader)).TryBeginRead((int)b)) { LCDirectLan.Log((LogLevel)4, $"SERVER: Unable to read client username, cannot read {b} bytes from reader !"); return; } byte[] bytes = new byte[b]; ((FastBufferReader)(ref reader)).ReadBytes(ref bytes, (int)b, 0); string @string = Encoding.ASCII.GetString(bytes); LCDirectLan.Log((LogLevel)32, $"SERVER: Changing Player #{actualPlayerIndex} username to: {@string}"); StartOfRound.Instance.allPlayerScripts[actualPlayerIndex].playerUsername = @string; LCDirectLan.Log((LogLevel)16, $"SERVER: Sucessfully changed Player #{actualPlayerIndex}'s username to: {@string}"); SendGlobalUsernameRefreshToClient(); } else { LCDirectLan.Log((LogLevel)4, "SERVER: Client sent a broken payload, no UsernameLength !"); } } [ServerRpc] public static void ClientReceivedUsernameRefresh_ToServerRpc(ulong ClientID, FastBufferReader reader) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsServer) { return; } int actualPlayerIndex = allPlayerScripts.GetActualPlayerIndex(ClientID); LCDirectLan.Log((LogLevel)32, $"SERVER: Received UsernameBroadcastCallback from Client #{ClientID}, Player #{actualPlayerIndex} for BroadcastID #{PlayerSyncBroadcastID} !"); if (actualPlayerIndex == -1) { LCDirectLan.Log((LogLevel)4, $"SERVER: Player #{actualPlayerIndex} is not controlled by anyone, ignoring UsernameBroadcastCallback !"); } else if (((FastBufferReader)(ref reader)).TryBeginRead(1)) { byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValue<byte>(ref b, default(ForPrimitives)); if (b != PlayerSyncBroadcastID) { LCDirectLan.Log((LogLevel)4, $"SERVER: Player #{actualPlayerIndex} is lagging behind broadcast {b} !"); return; } if (actualPlayerIndex >= PlayerSyncStatus.Length) { LCDirectLan.Log((LogLevel)4, $"SERVER: Player #{actualPlayerIndex} is out of range in PlayerSyncStatus !"); return; } PlayerSyncStatus[actualPlayerIndex] = true; LCDirectLan.Log((LogLevel)16, $"SERVER: Player #{actualPlayerIndex} has successfully synced usernames !"); } else { LCDirectLan.Log((LogLevel)4, $"SERVER: Player #{actualPlayerIndex} sent a broken payload, no BroadcastID !"); } } private static void SendGlobalUsernameRefreshToClient() { //IL_01fe: Unknown result type (might be due to invalid IL or missing references) LCDirectLan.Log((LogLevel)32, "SendGlobalUsernameRefreshToClient()"); if (!NetworkManager.Singleton.IsServer) { LCDirectLan.Log((LogLevel)4, "CLIENT: Cannot send global username refresh as a client !!!"); return; } if (IsBroadcastingPlayerUsernames) { LCDirectLan.Log((LogLevel)4, "SERVER: Still trying to broadcast player usernames, ignoring request to broadcast again"); return; } IsBroadcastingPlayerUsernames = true; PlayerSyncStatus = new bool[StartOfRound.Instance.allPlayerScripts.Length]; for (int i = 0; i < PlayerSyncStatus.Length; i++) { PlayerSyncStatus[i] = false; } byte b; for (b = PlayerSyncBroadcastID; b == PlayerSyncBroadcastID; b = (byte)Random.Range(0, 255)) { } PlayerSyncBroadcastID = b; LCDirectLan.Log((LogLevel)16, $"SERVER: Sending all usernames available on the server to clients (BroadcastID: {PlayerSyncBroadcastID})..."); List<byte[]> list = new List<byte[]>(); int num = 0; list.Add(new byte[1] { b }); num++; int num2 = StartOfRound.Instance.allPlayerScripts.Length; list.Add(new byte[1] { (byte)num2 }); num++; for (int j = 0; j < num2; j++) { if (!StartOfRound.Instance.allPlayerScripts[j].isPlayerControlled) { LCDirectLan.Log((LogLevel)32, $"SERVER: Ignoring Player #{j} as they are not controlled by anyone"); list.Add(new byte[1]); num++; continue; } string playerUsername = StartOfRound.Instance.allPlayerScripts[j].playerUsername; int length = playerUsername.Length; list.Add(new byte[1] { (byte)length }); num++; list.Add(Encoding.ASCII.GetBytes(playerUsername)); num += length; LCDirectLan.Log((LogLevel)32, $"SERVER: Packed Player #{j} username: {playerUsername}"); } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, -1); for (int k = 0; k < list.Count; k++) { ((FastBufferWriter)(ref val)).WriteBytes(list[k], list[k].Length, 0); } ((MonoBehaviour)NetworkManager.Singleton).StartCoroutine(WaitForAllClientsToSyncUsernames()); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("LCDirectLAN_GlobalUsernameRefresh_ToClientRpc", val, (NetworkDelivery)2); LCDirectLan.Log((LogLevel)16, "SERVER: Sucessfully sent a global username refresh to all clients"); IsBroadcastingPlayerUsernames = false; } private static void SendUsernameRefreshToClient(ulong NetworkClientID) { //IL_01c6: Unknown result type (might be due to invalid IL or missing references) LCDirectLan.Log((LogLevel)32, $"SendUsernameRefreshToClient({NetworkClientID})"); if (!NetworkManager.Singleton.IsServer) { LCDirectLan.Log((LogLevel)4, "CLIENT: Cannot send username refresh as a client !!!"); return; } if (IsBroadcastingPlayerUsernames) { LCDirectLan.Log((LogLevel)4, "SERVER: Still trying to broadcast player usernames, ignoring request to broadcast again"); return; } IsBroadcastingPlayerUsernames = true; byte b = PlayerSyncBroadcastID; if (b == 0) { b = (PlayerSyncBroadcastID = (byte)Random.Range(0, 255)); } LCDirectLan.Log((LogLevel)16, $"SERVER: Sending all usernames available on the server to client #{NetworkClientID} (BroadcastID: {PlayerSyncBroadcastID})..."); List<byte[]> list = new List<byte[]>(); int num = 0; list.Add(new byte[1] { b }); num++; int num2 = StartOfRound.Instance.allPlayerScripts.Length; list.Add(new byte[1] { (byte)num2 }); num++; for (int i = 0; i < num2; i++) { if (!StartOfRound.Instance.allPlayerScripts[i].isPlayerControlled) { LCDirectLan.Log((LogLevel)32, $"SERVER: Ignoring Player #{i} as they are not controlled by anyone"); list.Add(new byte[1]); num++; continue; } string playerUsername = StartOfRound.Instance.allPlayerScripts[i].playerUsername; int length = playerUsername.Length; list.Add(new byte[1] { (byte)length }); num++; list.Add(Encoding.ASCII.GetBytes(playerUsername)); num += 1 + length; LCDirectLan.Log((LogLevel)32, $"SERVER: Packed Player #{i} username: {playerUsername}"); } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, -1); for (int j = 0; j < list.Count; j++) { ((FastBufferWriter)(ref val)).WriteBytes(list[j], list[j].Length, 0); } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LCDirectLAN_GlobalUsernameRefresh_ToClientRpc", NetworkClientID, val, (NetworkDelivery)2); LCDirectLan.Log((LogLevel)16, $"SERVER: Sucessfully sent a username refresh to client #{NetworkClientID}"); IsBroadcastingPlayerUsernames = false; } private static IEnumerator WaitForAllClientsToSyncUsernames() { LCDirectLan.Log((LogLevel)32, "WaitForAllClientsToSyncUsernames()"); if (!NetworkManager.Singleton.IsServer) { LCDirectLan.Log((LogLevel)4, "CLIENT: Cannot wait for all clients to sync usernames as a client !!!"); yield break; } yield return (object)new WaitForSeconds(1f); byte TargetBroadcastID = PlayerSyncBroadcastID; float TargetWaitTimeout = Time.time + (float)(int)PlayerSyncWaitTimeout; int RefreshInterval = PlayerSyncWaitTimeout / 10; while (true) { if (Time.time > TargetWaitTimeout) { LCDirectLan.Log((LogLevel)4, "SERVER: Reached Username Sync Timeout, Some clients may not have synced their usernames !"); for (int i = 0; i < PlayerSyncStatus.Length; i++) { if (StartOfRound.Instance.allPlayerScripts[i].isPlayerControlled) { LCDirectLan.Log((LogLevel)4, $"SERVER: Is Client #{i} ({StartOfRound.Instance.allPlayerScripts[i].playerUsername}) has reported they are synced: {PlayerSyncStatus[i]}"); } } break; } if (TargetBroadcastID != PlayerSyncBroadcastID) { LCDirectLan.Log((LogLevel)4, $"SERVER: Broadcast ID mismatch, aborting wait for current sync: {TargetBroadcastID} != {PlayerSyncBroadcastID} !"); break; } bool flag = true; for (int j = 0; j < PlayerSyncStatus.Length; j++) { if (StartOfRound.Instance.allPlayerScripts[j].isPlayerControlled && !PlayerSyncStatus[j]) { flag = false; LCDirectLan.Log((LogLevel)4, $"SERVER: Player #{j} ({StartOfRound.Instance.allPlayerScripts[j].playerUsername}) has not reported their username are synced, resending..."); SendUsernameRefreshToClient(StartOfRound.Instance.allPlayerScripts[j].actualClientId); break; } } if (flag) { break; } yield return (object)new WaitForSeconds((float)RefreshInterval); } if (Time.time > TargetWaitTimeout) { HUDManager.Instance.DisplayTip("LCDirectLAN", "Some clients may not have synced their usernames properly", false, false, "LC_Tip1"); yield break; } LCDirectLan.Log((LogLevel)16, "SERVER: All clients have successfully synced their usernames !"); PlayerSyncBroadcastID = 0; } public static void SendInformationToServerRpc(string username) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (!NetworkManager.Singleton.IsClient) { return; } LCDirectLan.Log((LogLevel)16, "CLIENT: Trying to send our username (" + username + ") to server"); if (username == string.Empty) { LCDirectLan.Log((LogLevel)2, "CLIENT: Cannot send empty username !"); return; } byte[] bytes = Encoding.ASCII.GetBytes(username); if (bytes.Length > 255) { LCDirectLan.Log((LogLevel)2, $"CLIENT: Cannot send username, too long ({bytes.Length}) !"); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1 + bytes.Length, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteByte((byte)bytes.Length); ((FastBufferWriter)(ref val)).WriteBytes(bytes, bytes.Length, 0); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LCDirectLAN_ClientUsernameChanged_ToServerRpc", 0uL, val, (NetworkDelivery)2); LCDirectLan.Log((LogLevel)32, "CLIENT: Sucessfully sent our username (" + username + ") to server"); } [ClientRpc] public static void GlobalUsernameRefresh_ToClientRpc(ulong ClientID, FastBufferReader reader) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) LCDirectLan.Log((LogLevel)16, "CLIENT: Got GlobalUsernameRefresh from Server !"); if (!NetworkManager.Singleton.IsClient) { return; } if (!((FastBufferReader)(ref reader)).TryBeginRead(1)) { LCDirectLan.Log((LogLevel)4, "CLIENT: Server sent a broken GlobalUsernameRefresh payload, no BroadcastID !"); return; } byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValue<byte>(ref b, default(ForPrimitives)); if (!((FastBufferReader)(ref reader)).TryBeginRead(1)) { LCDirectLan.Log((LogLevel)4, "CLIENT: Server sent a broken GlobalUsernameRefresh payload, no PlayerCount !"); return; } byte b2 = default(byte); ((FastBufferReader)(ref reader)).ReadValue<byte>(ref b2, default(ForPrimitives)); if (b2 != StartOfRound.Instance.allPlayerScripts.Length) { LCDirectLan.Log((LogLevel)4, $"CLIENT: Server sent a GlobalUsernameRefresh with {b2} players, but we only have {StartOfRound.Instance.allPlayerScripts.Length} players !"); return; } QuickMenuManager val = Object.FindObjectOfType<QuickMenuManager>(); byte b3 = default(byte); for (int i = 0; i < b2; i++) { if (!((FastBufferReader)(ref reader)).TryBeginRead(1)) { LCDirectLan.Log((LogLevel)2, "CLIENT: Server sent a broken GlobalUsernameRefresh payload, no UsernameLength !\nThe lobby host may be using a mod that increases the maximum player count in lobby that did not get synced to you."); return; } ((FastBufferReader)(ref reader)).ReadValue<byte>(ref b3, default(ForPrimitives)); if (b3 == 0) { if (!StartOfRound.Instance.allPlayerScripts[i].isPlayerControlled) { LCDirectLan.Log((LogLevel)32, $"CLIENT: Server ignored username for Player #{i} (Not controlled)"); } else { LCDirectLan.Log((LogLevel)4, $"CLIENT: Server sent a empty username for Player #{i}, ignoring !"); } continue; } if (!((FastBufferReader)(ref reader)).TryBeginRead((int)b3)) { LCDirectLan.Log((LogLevel)4, $"CLIENT: Server sent a broken GlobalUsernameRefresh payload, cannot read {b3} bytes from reader for the Player #{i} !"); return; } byte[] bytes = new byte[b3]; ((FastBufferReader)(ref reader)).ReadBytes(ref bytes, (int)b3, 0); string @string = Encoding.ASCII.GetString(bytes); LCDirectLan.Log((LogLevel)32, $"CLIENT: Unpacked Player #{i} username: {@string}"); bool flag = false; if (i < StartOfRound.Instance.allPlayerScripts.Length) { StartOfRound.Instance.allPlayerScripts[i].playerUsername = @string; ((TMP_Text)StartOfRound.Instance.allPlayerScripts[i].usernameBillboardText).text = @string; } else { flag = true; LCDirectLan.Log((LogLevel)4, $"CLIENT: Cannot set StartOfRound.allPlayerScripts[{i}], it only has {StartOfRound.Instance.allPlayerScripts.Length} elements"); } if (i < val.playerListSlots.Length) { ((TMP_Text)val.playerListSlots[i].usernameHeader).text = @string; } else { flag = true; LCDirectLan.Log((LogLevel)4, $"CLIENT: Cannot set quickMenuManager.playerListSlots[{i}], it only has {val.playerListSlots} elements"); } if (i < StartOfRound.Instance.mapScreen.radarTargets.Count) { StartOfRound.Instance.mapScreen.radarTargets[i].name = @string; } else { flag = true; LCDirectLan.Log((LogLevel)4, $"CLIENT: Cannot set StartOfRound.mapScreen.radarTargets[{i}], it only has {StartOfRound.Instance.mapScreen.radarTargets} elements"); } if (flag) { LCDirectLan.Log((LogLevel)4, $"CLIENT: Some problem occured while changing Player #{i}'s username to: {@string}]\nThe lobby host may be using a mod that increases the maximum player count in lobby that did not get synced to you."); return; } LCDirectLan.Log((LogLevel)16, $"CLIENT: Sucessfully changed Player #{i}'s username to: {@string}"); } StartOfRoundPatch.LatePatch_PlayerNameOnMapScreen(); FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(1, (Allocator)2, -1); ((FastBufferWriter)(ref val2)).WriteByte(b); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LCDirectLAN_ClientReceivedUsernameRefresh_ToServerRpc", 0uL, val2, (NetworkDelivery)2); } } } namespace LCDirectLAN.Patches.ConfigurableLAN { internal class PlayerJoinData { public string Address; public string Username; private ushort _Port; private bool _IsPortValid; public ushort Port { get { return _Port; } private set { _Port = value; } } public bool IsPortValid { get { return _IsPortValid; } private set { _IsPortValid = value; } } public PlayerJoinData() { Address = ""; Username = ""; SetPort("7777"); } public PlayerJoinData(string address = "", string port = "7777", string username = "") { Address = address; Username = username; SetPort(port); } public PlayerJoinData(string address = "", ushort port = 7777, string username = "") { Address = address; Username = username; SetPort(port.ToString()); } public bool SetPort(string RawPort) { if (!ushort.TryParse(RawPort, out var result)) { return false; } if (result < 1) { return false; } IsPortValid = true; Port = result; return true; } public void ClearPort() { Port = 0; IsPortValid = false; } } [HarmonyPatch(typeof(MenuManager))] internal class MenuManagerPatch { private static readonly int UsernameLengthLimit = 30; private static GameObject DirectJoinObj; private static GameObject DirectConnectWindow; private static byte HideJoinData = 3; private static PlayerJoinData PublicServerJoinData = null; private static PlayerJoinData PrivateServerJoinData = null; private static bool IsSyncingUIWithData = false; private static MenuManager __MenuManager; [HarmonyPatch("Start")] [HarmonyPostfix] [HarmonyPriority(100)] public static void PrepareDirectLANDialog(MenuManager __instance, ref bool ___isInitScene) { if (___isInitScene) { return; } __MenuManager = __instance; PublicServerJoinData = new PlayerJoinData(LCDirectLan.GetConfig<string>("Join", "DefaultAddress"), LCDirectLan.GetConfig<ushort>("Join", "DefaultPort")); HideJoinData = LCDirectLan.GetConfig<byte>("Join", "HideRawJoinData"); if (LCDirectLan.GetConfig<bool>("Custom Username", "Enabled")) { PublicServerJoinData.Username = LCDirectLan.GetConfig<string>("Custom Username", "JoinDefaultUsername"); } LCDirectLan.Log((LogLevel)16, "Loaded JoinData from config file:"); LCDirectLan.Log((LogLevel)16, "Address: '" + PublicServerJoinData.Address + "'"); LCDirectLan.Log((LogLevel)16, $"Port: '{PublicServerJoinData.Port}'"); LCDirectLan.Log((LogLevel)16, "Username: '" + PublicServerJoinData.Username + "'"); if (HideJoinData > 0) { LCDirectLan.Log((LogLevel)16, $"Applying server leak protection based on HideRawJoinData's bitwise value: {HideJoinData}"); if ((HideJoinData & 1) == 1 && !string.IsNullOrEmpty(PublicServerJoinData.Address) && ResolveDNS.CheckIPType(PublicServerJoinData.Address) != AddressFamily.Unknown) { PublicServerJoinData.Address = ""; LCDirectLan.Log((LogLevel)16, "Server IP Address from config is cleared !"); } if ((HideJoinData & 2) == 2) { PublicServerJoinData.ClearPort(); LCDirectLan.Log((LogLevel)16, "Server Port value from config is cleared !"); } if ((HideJoinData & 4) == 4 && ResolveDNS.IsOnHostnameFormat(PublicServerJoinData.Address)) { PublicServerJoinData.Address = ""; LCDirectLan.Log((LogLevel)16, "Server Hostname value from config is cleared !"); } } if (LCDirectLan.GetConfig<bool>("Join", "CreateExtraButton")) { CreateDirectJoinButton(); } else { ReuseDirectJoinButton(); } if (LCDirectLan.GetConfig<bool>("Custom Username", "Enabled") && LCDirectLan.GetConfig<bool>("Custom Username", "CreateHostUsernameInput") && !LCDirectLan.GetConfig<bool>("Custom Username", "MergeDefaultUsername")) { CreateHostUsernameInputField(); } } private static void CreateDirectJoinButton() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown LCDirectLan.Log((LogLevel)32, "Creating a new LAN Join button !"); if (GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/MainButtons", out var obj) && GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/MainButtons/HostButton", out var obj2)) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(obj2.transform.position.x, obj2.transform.position.y - 3.5f, obj2.transform.position.z); ReadjustAllMenuButtons(obj); DirectJoinObj = Object.Instantiate<GameObject>(obj2, obj.transform); ((Object)DirectJoinObj.gameObject).name = "DirectJoinButton"; DirectJoinObj.transform.SetPositionAndRotation(val, DirectJoinObj.transform.rotation); DirectJoinObj.SetActive(true); ((TMP_Text)(TextMeshProUGUI)((Component)DirectJoinObj.transform.GetChild(1)).GetComponent("TextMeshProUGUI")).text = "> Direct LAN Join"; Button component = DirectJoinObj.GetComponent<Button>(); ((UnityEventBase)component.onClick).RemoveAllListeners(); ((UnityEvent)component.onClick).AddListener(new UnityAction(OnDirectJoinButtonClicked)); LCDirectLan.Log((LogLevel)32, "Instantiated DirectJoinButton"); } } private static void ReuseDirectJoinButton() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown LCDirectLan.Log((LogLevel)32, "Reusing the original LAN Join button !"); if (GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/MainButtons/StartLAN", out var obj)) { Button component = obj.GetComponent<Button>(); for (int i = 0; i < ((UnityEventBase)component.onClick).GetPersistentEventCount(); i++) { ((UnityEventBase)component.onClick).SetPersistentListenerState(i, (UnityEventCallState)0); } ((UnityEventBase)component.onClick).RemoveAllListeners(); ((UnityEvent)component.onClick).AddListener(new UnityAction(OnDirectJoinButtonClicked)); LCDirectLan.Log((LogLevel)32, "Successfully Reused Buttons for DirectJoinButton"); } } private static void CreateDirectConnectWindow() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_05db: Unknown result type (might be due to invalid IL or missing references) //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_0551: Unknown result type (might be due to invalid IL or missing references) //IL_0620: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Expected O, but got Unknown //IL_065c: Unknown result type (might be due to invalid IL or missing references) //IL_0677: Unknown result type (might be due to invalid IL or missing references) //IL_06a1: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Unknown result type (might be due to invalid IL or missing references) //IL_0716: Unknown result type (might be due to invalid IL or missing references) //IL_073e: Unknown result type (might be due to invalid IL or missing references) //IL_0748: Expected O, but got Unknown if (!GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer", out var obj) || !GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings", out var obj2)) { return; } DirectConnectWindow = Object.Instantiate<GameObject>(obj2, obj.transform); ((Object)DirectConnectWindow.gameObject).name = "DirectConnectWindow"; DirectConnectWindow.transform.SetLocalPositionAndRotation(new Vector3(0f, 0f, 0f), DirectConnectWindow.transform.localRotation); DirectConnectWindow.SetActive(false); LCDirectLan.Log((LogLevel)32, "Sucessfully Instantiate DirectConnectWindow"); Object.Destroy((Object)(object)((Component)DirectConnectWindow.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)DirectConnectWindow.transform.GetChild(2)).gameObject); GameObject gameObject = ((Component)DirectConnectWindow.transform.GetChild(1)).gameObject; if ((Object)(object)gameObject == (Object)null) { LCDirectLan.Log((LogLevel)2, "Cannot find HostSettingsContainer !"); return; } ((Object)gameObject).name = "DCSettingsContainer"; gameObject.GetComponent<RectTransform>().SetSizeWithCurrentAnchors((Axis)0, 250f); gameObject.GetComponent<RectTransform>().SetSizeWithCurrentAnchors((Axis)1, 270f); gameObject.SetActive(true); if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/HostUsernameLabel")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/HostUsernameLabel"); } if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/HostUsernameField")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/HostUsernameField"); } if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/PrivatePublicDescription")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/PrivatePublicDescription"); } if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/tipText")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/tipText"); } if (!GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions", out var obj3)) { return; } if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/LANOptions")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/LANOptions"); } GameObject gameObject2 = ((Component)obj3.transform.GetChild(0)).gameObject; if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/OptionsNormal/Public")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/OptionsNormal/Public"); } if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/OptionsNormal/Private")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/OptionsNormal/Private"); } if (GameObjectManager.IsExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/OptionsNormal/ServerTagInputField")) { GameObjectManager.DeleteGameObject("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/LobbyHostOptions/OptionsNormal/ServerTagInputField"); } ((Component)gameObject2.transform.Find("EnterAName")).transform.SetParent(gameObject.transform, true); ((Component)gameObject2.transform.Find("ServerNameField")).transform.SetParent(gameObject.transform, true); Object.Destroy((Object)(object)gameObject2); Object.Destroy((Object)(object)obj3); GameObject gameObject3 = ((Component)gameObject.transform.Find("EnterAName")).gameObject; ((Object)gameObject3).name = "AddressInputLabel"; gameObject3.transform.SetLocalPositionAndRotation(new Vector3(-35f, 131f, 0f), gameObject3.transform.localRotation); GameObject val = Object.Instantiate<GameObject>(gameObject3, gameObject.transform); ((Object)val).name = "PortInputLabel"; val.transform.SetLocalPositionAndRotation(new Vector3(-64f, 83f, 0f), gameObject3.transform.localRotation); if (LCDirectLan.GetConfig<bool>("Custom Username", "Enabled")) { GameObject obj4 = Object.Instantiate<GameObject>(gameObject3, gameObject.transform); ((Object)obj4).name = "UsernameInputLabel"; obj4.transform.SetLocalPositionAndRotation(new Vector3(-64f, 33f, 0f), gameObject3.transform.localRotation); ((TMP_Text)obj4.GetComponent<TextMeshProUGUI>()).text = "My Username: "; } GameObject obj5 = Object.Instantiate<GameObject>(gameObject3, gameObject.transform); ((Object)obj5).name = "LCDirectLANPoweredByLabel"; obj5.transform.SetLocalPositionAndRotation(new Vector3(-0.5f, -110f, 0f), gameObject3.transform.localRotation); ((TMP_Text)val.GetComponent<TextMeshProUGUI>()).text = "Server Port:"; ((TMP_Text)gameObject3.GetComponent<TextMeshProUGUI>()).text = "Server IP/Hostname:"; TextMeshProUGUI component = obj5.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).text = "Powered by TIRTAGT/LCDirectLAN"; ((TMP_Text)component).alpha = 0.3f; ((TMP_Text)component).fontSizeMin = 13f; ((TMP_Text)component).fontSize = 13f; GameObject gameObject4 = ((Component)gameObject.transform.Find("ServerNameField")).gameObject; gameObject4.transform.SetLocalPositionAndRotation(new Vector3(0f, 110f, 0f), gameObject4.transform.localRotation); TMP_InputField component2 = gameObject4.GetComponent<TMP_InputField>(); ((TMP_Text)(TextMeshProUGUI)component2.placeholder).text = ""; component2.text = ""; ((UnityEvent<string>)(object)component2.onValueChanged).AddListener((UnityAction<string>)OnServerNameInputField_Changed); GameObject val2 = Object.Instantiate<GameObject>(gameObject4, gameObject.transform); ((Object)val2).name = "ServerPortField"; val2.transform.SetLocalPositionAndRotation(new Vector3(0f, 62f, 0f), val2.transform.localRotation); TMP_InputField component3 = val2.GetComponent<TMP_InputField>(); ((TMP_Text)(TextMeshProUGUI)component3.placeholder).text = LCDirectLan.GetConfig<ushort>("Join", "DefaultPort").ToString(); component3.text = ""; ((UnityEvent<string>)(object)component3.onValueChanged).AddListener((UnityAction<string>)OnServerPortInputField_Changed); if (LCDirectLan.GetConfig<bool>("Custom Username", "Enabled")) { GameObject val3 = Object.Instantiate<GameObject>(gameObject4, gameObject.transform); ((Object)val3).name = "CustomUsernameField"; val3.transform.SetLocalPositionAndRotation(new Vector3(0f, 10.5f, 0f), val3.transform.localRotation); TMP_InputField component4 = val3.GetComponent<TMP_InputField>(); ((TMP_Text)(TextMeshProUGUI)component4.placeholder).text = "Lethal Player"; component4.text = LCDirectLan.GetConfig<string>("Custom Username", "JoinDefaultUsername"); component4.characterLimit = UsernameLengthLimit; ((UnityEvent<string>)(object)component4.onValueChanged).AddListener((UnityAction<string>)OnUsernameInputField_Changed); } LCDirectLan.Log((LogLevel)32, "Sucessfully Instantiate input fields"); GameObject gameObject5 = ((Component)gameObject.transform.Find("Confirm")).gameObject; gameObject5.transform.SetLocalPositionAndRotation(new Vector3(0f, -50f, 0f), gameObject5.transform.localRotation); Button component5 = gameObject5.GetComponent<Button>(); if ((Object)(object)component5 == (Object)null) { LCDirectLan.Log((LogLevel)2, "Cannot create Button component for ConfirmButton !"); return; } ((UnityEventBase)component5.onClick).SetPersistentListenerState(0, (UnityEventCallState)0); ((UnityEvent)component5.onClick).AddListener(new UnityAction(OnDirectJoinConnect)); ((Component)component5).GetComponent<RectTransform>().SetSizeWithCurrentAnchors((Axis)0, 250f); ((Component)component5).transform.Find("SelectionHighlight").SetLocalPositionAndRotation(new Vector3(0.5f, 0.443f, 0.798f), ((Component)((Component)component5).transform.Find("SelectionHighlight")).transform.localRotation); ((Component)((Component)component5).transform.Find("SelectionHighlight")).GetComponent<RectTransform>().sizeDelta = new Vector2(210f, 25.191f); LCDirectLan.Log((LogLevel)32, "Sucessfully taken care of onClickListener on ConfirmButtonObj"); ((TMP_Text)((Component)((Component)gameObject5.transform.GetChild(1)).gameObject.transform).GetComponent<TextMeshProUGUI>()).text = "[ Connect To Server ]"; GameObject gameObject6 = ((Component)gameObject.transform.Find("Back")).gameObject; gameObject6.transform.SetLocalPositionAndRotation(new Vector3(0f, -90f, 0f), gameObject6.transform.localRotation); Button component6 = gameObject6.GetComponent<Button>(); ((UnityEventBase)component6.onClick).RemoveAllListeners(); ((UnityEvent)component6.onClick).AddListener(new UnityAction(OnDirectJoinBack)); LCDirectLan.Log((LogLevel)32, "Sucessfully Replaced onClickListener on BackButtonObj"); SetInputTextField(gameObject4, PublicServerJoinData.Address); if (PublicServerJoinData.IsPortValid) { SetInputTextField(val2, PublicServerJoinData.Port.ToString()); } LCDirectLan.Log((LogLevel)32, "Instantiated DirectConnectSettings"); } private static void ReadjustAllMenuButtons(GameObject _MainButtons) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) (string, float)[] array = new(string, float)[4] { ("HostButton", -3f), ("StartLAN", 3.3f), ("SettingsButton", 2f), ("Credits", 1f) }; Vector3 val2 = default(Vector3); for (int i = 0; i < array.Length; i++) { (string, float) tuple = array[i]; Transform val = _MainButtons.transform.Find(tuple.Item1); if ((Object)(object)val == (Object)null) { LCDirectLan.Log((LogLevel)2, "Cannot find " + tuple.Item1 + " in MenuButtons !"); continue; } GameObject gameObject = ((Component)val).gameObject; Vector3 position = gameObject.transform.position; ((Vector3)(ref val2))..ctor(position.x, position.y - tuple.Item2, position.z); gameObject.transform.SetPositionAndRotation(val2, gameObject.transform.rotation); } } private static string GetInputTextField(GameObject TextArea) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) TMP_InputField component = TextArea.gameObject.GetComponent<TMP_InputField>(); if ((Object)(object)component == (Object)null) { LCDirectLan.Log((LogLevel)4, "GetTextFromInputField() called on GameObject with no TMP_InputField"); return ""; } string text = component.text; if (text == null || text.Length == 0) { text = ((TMP_Text)(TextMeshProUGUI)component.placeholder).text; } return text; } private static bool SetInputTextField(GameObject TextArea, string Text) { TMP_InputField component = TextArea.gameObject.GetComponent<TMP_InputField>(); if ((Object)(object)component == (Object)null) { LCDirectLan.Log((LogLevel)4, "SetTextFromInputField() called on GameObject with no TMP_InputField"); return false; } component.text = Text; LCDirectLan.Log((LogLevel)32, "SetTextFromInputField(" + ((Object)TextArea).name + ", '" + Text + "') executed."); return true; } private static void OnDirectJoinButtonClicked() { if ((Object)(object)DirectConnectWindow == (Object)null) { CreateDirectConnectWindow(); } DirectConnectWindow.SetActive(true); } private static void OnServerNameInputField_Changed(string value) { PublicServerJoinData.Address = value; if (!IsSyncingUIWithData) { PrivateServerJoinData = null; } } private static void OnServerPortInputField_Changed(string value) { value = value.Trim(); if (string.IsNullOrEmpty(value)) { PublicServerJoinData.ClearPort(); return; } PublicServerJoinData.SetPort(value); if (!IsSyncingUIWithData) { PrivateServerJoinData = null; } } private static void OnUsernameInputField_Changed(string value) { PublicServerJoinData.Username = value; } private static void OnDirectJoinConnect() { DirectConnectWindow.SetActive(false); SetLoadingText("Connecting to server"); __MenuManager.SetLoadingScreen(true, (RoomEnter)5, ""); if (PrivateServerJoinData == null) { PublicServerJoinData.Address = PublicServerJoinData.Address.Trim(); if (string.IsNullOrEmpty(PublicServerJoinData.Address)) { LCDirectLan.Log((LogLevel)2, "Server IP/Hostname is empty"); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Server IP/Hostname is empty"); return; } if (!ResolveDNS.IsOnHostnameFormat(PublicServerJoinData.Address) && !PublicServerJoinData.IsPortValid) { if (PublicServerJoinData.Port != 0) { LCDirectLan.Log((LogLevel)2, "Invalid Server Port, please check the input field"); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Invalid Server Port, please check the input field"); PublicServerJoinData.ClearPort(); SyncUIWithPublicJoinData(); return; } PublicServerJoinData.SetPort(LCDirectLan.GetConfig<ushort>("Join", "DefaultPort").ToString()); LCDirectLan.Log((LogLevel)16, "Port is empty, using default port from config"); } if (LCDirectLan.GetConfig<bool>("Custom Username", "Enabled")) { if (PublicServerJoinData.Username.Length <= 0) { LCDirectLan.Log((LogLevel)2, $"Username too short, make sure the username is between 1 to {UsernameLengthLimit} ASCII characters"); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Username too short, make sure username is between 1 to 30 ASCII characters"); return; } if (PublicServerJoinData.Username.Length > UsernameLengthLimit) { LCDirectLan.Log((LogLevel)2, $"Username too long, make sure the username is between 1 to {UsernameLengthLimit} ASCII characters"); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Username too long, make sure username is between 1 to 30 ASCII characters"); return; } } PrivateServerJoinData = new PlayerJoinData(PublicServerJoinData.Address, PublicServerJoinData.Port, PublicServerJoinData.Username); LCDirectLan.Log((LogLevel)16, "DirectJoin Connect clicked !"); LCDirectLan.Log((LogLevel)16, "IP: '" + PrivateServerJoinData.Address + "'"); LCDirectLan.Log((LogLevel)16, $"PORT: '{PrivateServerJoinData.Port}'"); LCDirectLan.Log((LogLevel)16, "Username: '" + PrivateServerJoinData.Username + "'"); } if (ResolveDNS.CheckIPType(PrivateServerJoinData.Address) == AddressFamily.Unknown && ResolveDNS.IsOnHostnameFormat(PrivateServerJoinData.Address)) { LCDirectLan.Log((LogLevel)16, "Detected a valid hostname, trying to resolve it..."); ((MonoBehaviour)__MenuManager).StartCoroutine(PerformDNSAutoConfigure(PrivateServerJoinData.Address, silent_resolve: false, delegate(PlayerJoinData ResolvedData) { if (ResolvedData == null) { OnDirectJoinBack(); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Unable to fetch server configuration data using DNS, make sure the hostname is correct and your DNS Provider supports it"); } else { PrivateServerJoinData.Address = ResolvedData.Address; if (ResolvedData.IsPortValid) { PrivateServerJoinData.SetPort(ResolvedData.Port.ToString()); } bool flag = false; if ((HideJoinData & 1) == 0) { PublicServerJoinData.Address = PrivateServerJoinData.Address; flag = true; } if ((HideJoinData & 2) == 0) { PublicServerJoinData.SetPort(PrivateServerJoinData.Port.ToString()); flag = true; } if (!flag) { SyncUIWithPublicJoinData(); LCDirectLan.Log((LogLevel)32, "Synced UI to the resolved server data !"); } ContinueDirectJoinConnect(); } })); } else { ContinueDirectJoinConnect(); } } private static void ContinueDirectJoinConnect() { if (ResolveDNS.CheckIPType(PrivateServerJoinData.Address) == AddressFamily.Unknown) { LCDirectLan.Log((LogLevel)2, "Invalid Server IP/Hostname (final check)"); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Invalid Server IP/Hostname"); return; } if (!PrivateServerJoinData.IsPortValid) { LCDirectLan.Log((LogLevel)2, "Invalid Server Port (final check)"); __MenuManager.SetLoadingScreen(false, (RoomEnter)5, "Invalid Server Port"); return; } if (LCDirectLan.GetConfig<bool>("Custom Username", "Enabled")) { LCDirectLan.SetConfig("Custom Username", "JoinDefaultUsername", PrivateServerJoinData.Username); } if (LCDirectLan.GetConfig<bool>("Join", "RememberLastJoinSettings")) { if (((HideJoinData & 1) != 1 || ResolveDNS.CheckIPType(PublicServerJoinData.Address) == AddressFamily.Unknown) && ((HideJoinData & 4) != 4 || !ResolveDNS.IsOnHostnameFormat(PublicServerJoinData.Address))) { LCDirectLan.SetConfig("Join", "DefaultAddress", PublicServerJoinData.Address); } if ((HideJoinData & 2) == 0) { LCDirectLan.SetConfig("Join", "DefaultPort", PrivateServerJoinData.Port); } LCDirectLan.SaveConfig(); } UnityTransport component = GameObject.Find("NetworkManager").GetComponent<UnityTransport>(); component.ConnectionData.Address = PrivateServerJoinData.Address; component.ConnectionData.Port = PrivateServerJoinData.Port; LCDirectLan.Log((LogLevel)16, $"Connecting to {PrivateServerJoinData.Address}:{PrivateServerJoinData.Port}"); string text = "Connecting to "; text = ((((uint)HideJoinData & (true ? 1u : 0u)) != 0) ? (text + "server") : (text + PrivateServerJoinData.Address)); if ((HideJoinData & 2) == 0) { text += $":{PrivateServerJoinData.Port}"; } SetLoadingText(text); GameObject.Find("MenuManager").GetComponent<MenuManager>().StartAClient(); } private static void SyncUIWithPublicJoinData() { GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/ServerNameField", out var obj); GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/ServerPortField", out var obj2); GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/DirectConnectWindow/DCSettingsContainer/CustomUsernameField", out var obj3); IsSyncingUIWithData = true; SetInputTextField(obj, PublicServerJoinData.Address); if (PublicServerJoinData.IsPortValid) { SetInputTextField(obj2, PublicServerJoinData.Port.ToString()); } else { SetInputTextField(obj2, ""); } if ((Object)(object)obj3 != (Object)null) { SetInputTextField(obj3, PublicServerJoinData.Username); } IsSyncingUIWithData = false; } private static void OnDirectJoinBack() { if (!((Object)(object)DirectConnectWindow == (Object)null)) { DirectConnectWindow.SetActive(false); } } private static IEnumerator PerformDNSAutoConfigure(string RecordName, bool silent_resolve = false, Action<PlayerJoinData> callback = null) { PlayerJoinData ResolvedServerData = new PlayerJoinData(string.Empty, 0, string.Empty); if (!silent_resolve) { SetLoadingText("Trying to fetch configuration using DNS..."); yield return (object)new WaitForSeconds(0.25f); } LCDirectLan.Log((LogLevel)16, "Trying to DNS SRV resolve: " + RecordName); if (!silent_resolve) { SetLoadingText("Resolving target host with DNS (SRV)..."); yield return (object)new WaitForSeconds(0.25f); } (string, ushort) tuple = ResolveDNS.ResolveSRVRecord(RecordName); if (tuple.Item1.Length > 0 || tuple.Item2 > 0) { (ResolvedServerData.Address, _) = tuple; ResolvedServerData.SetPort(tuple.Item2.ToString()); LCDirectLan.Log((LogLevel)16, $"Resolved SRV for '{RecordName}' as: {ResolvedServerData.Address}:{ResolvedServerData.Port}"); callback?.Invoke(ResolvedServerData); yield break; } LCDirectLan.Log((LogLevel)16, "Trying to use DNS TXT resolve: " + RecordName); if (!silent_resolve) { SetLoadingText("Resolving target host with DNS (TXT)..."); yield return (object)new WaitForSeconds(0.25f); } string text = ResolveDNS.ResolveTXTRecord(RecordName); if (text.Length > "LCDirectLAN".Length + 2) { LCDirectLan.Log((LogLevel)32, "Got TXT Data: " + text); if (text.StartsWith("LCDirectLAN_")) { text = text.Substring("LCDirectLAN".Length + 1); int num = text.IndexOf(":"); if (num != -1) { string address = text.Substring(0, num); num++; if (ushort.TryParse(text.Substring(num), out var result)) { ResolvedServerData.Address = address; ResolvedServerData.SetPort(result.ToString()); LCDirectLan.Log((LogLevel)16, $"Resolved TXT for '{RecordName}' as: {ResolvedServerData.Address}:{ResolvedServerData.Port}"); callback?.Invoke(ResolvedServerData); yield break; } } } } LCDirectLan.Log((LogLevel)16, "Trying to use DNS AAAA resolve: " + RecordName); if (!silent_resolve) { SetLoadingText("Resolving target host with DNS (AAAA)..."); yield return (object)new WaitForSeconds(0.25f); } string text2 = ResolveDNS.ResolveAAAARecord(RecordName); if (text2.Length > 0) { ResolvedServerData.Address = text2; LCDirectLan.Log((LogLevel)16, "Resolved AAAA for '" + RecordName + "' as: " + ResolvedServerData.Address); callback?.Invoke(ResolvedServerData); yield break; } LCDirectLan.Log((LogLevel)16, "Trying to use DNS A resolve: " + RecordName); if (!silent_resolve) { SetLoadingText("Resolving target host with DNS (A)..."); yield return (object)new WaitForSeconds(0.25f); } string text3 = ResolveDNS.ResolveARecord(RecordName); if (text3.Length > 0) { ResolvedServerData.Address = text3; LCDirectLan.Log((LogLevel)16, "Resolved A for '" + RecordName + "' as: " + ResolvedServerData.Address); callback?.Invoke(ResolvedServerData); } else { LCDirectLan.Log((LogLevel)2, "Unable to resolve anything for hostname '" + RecordName + "'"); callback?.Invoke(null); } } [HarmonyPatch("ClickHostButton")] [HarmonyPrefix] [HarmonyPriority(100)] public static void Prefix_ClickHostButton() { GameObject.Find("NetworkManager").GetComponent<UnityTransport>().ConnectionData.Port = LCDirectLan.GetConfig<ushort>("Host", "DefaultPort"); } [HarmonyPatch("StartHosting")] [HarmonyPrefix] [HarmonyPriority(100)] public static void Prefix_StartHosting() { if (LCDirectLan.GetConfig<bool>("Host", "ListenOnIPv6")) { if (GameObject.Find("NetworkManager").GetComponent<UnityTransport>().ConnectionData.ServerListenAddress == "127.0.0.1") { GameObject.Find("NetworkManager").GetComponent<UnityTransport>().ConnectionData.ServerListenAddress = "::1"; LCDirectLan.Log((LogLevel)32, "Server Listen Address changed to IPv6 Localhost/Loopback (::1)"); } else { GameObject.Find("NetworkManager").GetComponent<UnityTransport>().ConnectionData.ServerListenAddress = "::"; LCDirectLan.Log((LogLevel)32, "Server Listen Address changed to IPv6 Any Address (::1)"); } } } private static void SetLoadingText(string text) { if (!string.IsNullOrEmpty(text)) { ((TMP_Text)GameObject.Find("Canvas/MenuContainer/LoadingScreen/LoadingTextContainer/LoadingText").GetComponent<TextMeshProUGUI>()).text = text; } } public static void CreateHostUsernameInputField() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) if (!GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer", out var obj)) { return; } Vector3 config = LCDirectLan.GetConfig<Vector3>("Custom Username", "HostUsernameInput_Offset_Y"); obj.GetComponent<RectTransform>().SetSizeWithCurrentAnchors((Axis)1, 205f); if (!GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer/LobbyHostOptions", out var obj2)) { return; } Vector3 position = obj2.transform.position; obj2.transform.SetPositionAndRotation(new Vector3(position.x, position.y + ((Vector3)(ref config))[0], position.z), obj2.transform.rotation); if (!GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer/Confirm", out var obj3)) { return; } position = obj3.transform.position; obj3.transform.SetPositionAndRotation(new Vector3(position.x, position.y + ((Vector3)(ref config))[1], position.z), obj3.transform.rotation); if (!GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer/Back", out var obj4)) { return; } position = obj4.transform.position; obj4.transform.SetPositionAndRotation(new Vector3(position.x, position.y + ((Vector3)(ref config))[2], position.z), obj4.transform.rotation); if (GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer/LobbyHostOptions/LANOptions/Header", out var obj5)) { GameObject val = Object.Instantiate<GameObject>(obj5, obj.transform); ((Object)val).name = "HostUsernameLabel"; val.transform.SetLocalPositionAndRotation(new Vector3(-74f, 2.5f, 0f), val.transform.localRotation); TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).text = "My Username: "; ((TMP_Text)component).fontSize = 13f; if (GameObjectManager.EnsureGameObjectExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer/LobbyHostOptions/LANOptions/ServerNameField", out var obj6)) { GameObject val2 = Object.Instantiate<GameObject>(obj6, obj.transform); ((Object)val2).name = "HostUsernameField"; val2.transform.SetLocalPositionAndRotation(new Vector3(0f, -27f, 0f), val2.transform.localRotation); val2.SetActive(true); ((TMP_Text)(TextMeshProUGUI)val2.GetComponent<TMP_InputField>().placeholder).text = LCDirectLan.GetConfig<string>("Custom Username", "HostDefaultUsername"); } } } [HarmonyPatch("ConfirmHostButton")] [HarmonyPrefix] [HarmonyPriority(100)] public static bool Prefix_ConfirmHostButton() { if (!GameObjectManager.IsExist("Canvas/MenuContainer/LobbyHostSettings/HostSettingsContainer/HostUsernameField", out var obj)) { return true; } string inputTextField = GetInputTextField(o
BepInEx/plugins/libs/DnsClient.1.7.0/DnsClient.dll
Decompiled 7 months ago
The result has been truncated due to the large size, download it to view full contents!
#define TRACE using System; using System.Buffers; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; using DnsClient.Internal; using DnsClient.Linux; using DnsClient.Protocol; using DnsClient.Protocol.Options; using DnsClient.Windows; using DnsClient.Windows.IpHlpApi; using Microsoft.Win32; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: CLSCompliant(true)] [assembly: InternalsVisibleTo("DnsClient.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100676f9d5ff1e268c55fda5578e9f09f27b5fdfadc2b96eec28616532974ffdab2551ac7082ef0037690e3f859328da8425afc284333a808f01b5bbef674a615723b1085b6404b293e10dc8132d5636b692edab794ada3f53711175f0520d3d84e217fc9269de230ee8ca90415f919514776435bff5cb94cad1652a90ead386fc1")] [assembly: InternalsVisibleTo("Benchmarks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100676f9d5ff1e268c55fda5578e9f09f27b5fdfadc2b96eec28616532974ffdab2551ac7082ef0037690e3f859328da8425afc284333a808f01b5bbef674a615723b1085b6404b293e10dc8132d5636b692edab794ada3f53711175f0520d3d84e217fc9269de230ee8ca90415f919514776435bff5cb94cad1652a90ead386fc1")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("MichaCo")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2021 Michael Conrad")] [assembly: AssemblyDescription("DnsClient.NET is a simple yet very powerful and high performance open source library for the .NET Framework to do DNS lookups")] [assembly: AssemblyFileVersion("1.7.0.0")] [assembly: AssemblyInformationalVersion("1.7.0")] [assembly: AssemblyProduct("DnsClient.NET")] [assembly: AssemblyTitle("DnsClient")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/MichaCo/DnsClient.NET")] [assembly: AssemblyVersion("1.7.0.0")] internal static class Interop { internal static class Libraries { internal const string IpHlpApi = "iphlpapi.dll"; } internal static class IpHlpApi { internal struct FIXED_INFO { public const int MAX_HOSTNAME_LEN = 128; public const int MAX_DOMAIN_NAME_LEN = 128; public const int MAX_SCOPE_ID_LEN = 256; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 132)] public string hostName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 132)] public string domainName; public IntPtr currentDnsServer; public IP_ADDR_STRING DnsServerList; public uint nodeType; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string scopeId; public bool enableRouting; public bool enableProxy; public bool enableDns; } internal struct IP_ADDR_STRING { public IntPtr Next; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string IpAddress; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string IpMask; public uint Context; } internal const uint ERROR_SUCCESS = 0u; internal const uint ERROR_INVALID_FUNCTION = 1u; internal const uint ERROR_NO_SUCH_DEVICE = 2u; internal const uint ERROR_INVALID_DATA = 13u; internal const uint ERROR_INVALID_PARAMETER = 87u; internal const uint ERROR_BUFFER_OVERFLOW = 111u; internal const uint ERROR_INSUFFICIENT_BUFFER = 122u; internal const uint ERROR_NO_DATA = 232u; internal const uint ERROR_IO_PENDING = 997u; internal const uint ERROR_NOT_FOUND = 1168u; [DllImport("iphlpapi.dll")] internal static extern uint GetAdaptersAddresses(AddressFamily family, uint flags, IntPtr pReserved, IntPtr adapterAddresses, ref uint outBufLen); [DllImport("iphlpapi.dll", ExactSpelling = true)] internal static extern uint GetNetworkParams(IntPtr pFixedInfo, ref uint pOutBufLen); } } namespace System.Threading.Tasks { internal static class TaskExtensions { public static async Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken) { TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>(); using (cancellationToken.Register(delegate(object s) { ((TaskCompletionSource<bool>)s).TrySetResult(result: true); }, taskCompletionSource)) { if (task != await Task.WhenAny(new Task[2] { task, taskCompletionSource.Task }).ConfigureAwait(continueOnCapturedContext: false)) { task.ContinueWith((Task<T> t) => t.Exception); throw new OperationCanceledException(cancellationToken); } } return await task.ConfigureAwait(continueOnCapturedContext: false); } } } namespace System.Linq { public static class RecordCollectionExtension { public static IEnumerable<AddressRecord> AddressRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<AddressRecord>(); } public static IEnumerable<ARecord> ARecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<ARecord>(); } public static IEnumerable<NsRecord> NsRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<NsRecord>(); } public static IEnumerable<CNameRecord> CnameRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<CNameRecord>(); } [CLSCompliant(false)] public static IEnumerable<SoaRecord> SoaRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<SoaRecord>(); } public static IEnumerable<MbRecord> MbRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<MbRecord>(); } public static IEnumerable<MgRecord> MgRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<MgRecord>(); } public static IEnumerable<MrRecord> MrRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<MrRecord>(); } public static IEnumerable<NullRecord> NullRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<NullRecord>(); } public static IEnumerable<WksRecord> WksRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<WksRecord>(); } public static IEnumerable<PtrRecord> PtrRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<PtrRecord>(); } public static IEnumerable<HInfoRecord> HInfoRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<HInfoRecord>(); } [CLSCompliant(false)] public static IEnumerable<MxRecord> MxRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<MxRecord>(); } public static IEnumerable<TxtRecord> TxtRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<TxtRecord>(); } public static IEnumerable<RpRecord> RpRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<RpRecord>(); } public static IEnumerable<AfsDbRecord> AfsDbRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<AfsDbRecord>(); } public static IEnumerable<AaaaRecord> AaaaRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<AaaaRecord>(); } [CLSCompliant(false)] public static IEnumerable<SrvRecord> SrvRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<SrvRecord>(); } public static IEnumerable<NAPtrRecord> NAPtrRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<NAPtrRecord>(); } public static IEnumerable<UriRecord> UriRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<UriRecord>(); } public static IEnumerable<CaaRecord> CaaRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<CaaRecord>(); } public static IEnumerable<TlsaRecord> TlsaRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<TlsaRecord>(); } public static IEnumerable<RRSigRecord> RRSigRecords(this IEnumerable<DnsResourceRecord> records) { return records.OfType<RRSigRecord>(); } public static IEnumerable<DnsResourceRecord> OfRecordType(this IEnumerable<DnsResourceRecord> records, ResourceRecordType type) { return records.Where((DnsResourceRecord p) => p.RecordType == type); } } } namespace System.Net { public static class IpAddressExtensions { public static string GetArpaName(this IPAddress ip) { byte[] addressBytes = ip.GetAddressBytes(); Array.Reverse(addressBytes); if (ip.AddressFamily == AddressFamily.InterNetworkV6) { return addressBytes.SelectMany((byte b) => new int[2] { b & 0xF, (b >> 4) & 0xF }).Aggregate(new StringBuilder(), (StringBuilder s, int b) => s.Append(b.ToString("x")).Append('.'))?.ToString() + "ip6.arpa."; } if (ip.AddressFamily == AddressFamily.InterNetwork) { return string.Join(".", addressBytes) + ".in-addr.arpa."; } throw new ArgumentException($"Unsupported address family '{ip.AddressFamily}'.", "ip"); } } } namespace System.IO { internal struct RowConfigReader { private readonly string _buffer; private readonly StringComparison _comparisonKind; private int _currentIndex; public RowConfigReader(string buffer) { _buffer = buffer; _comparisonKind = StringComparison.Ordinal; _currentIndex = 0; } public RowConfigReader(string buffer, StringComparison comparisonKind) { _buffer = buffer; _comparisonKind = comparisonKind; _currentIndex = 0; } public string GetNextValue(string key) { if (!TryGetNextValue(key, out var value)) { throw new InvalidOperationException("Couldn't get next value with key " + key); } return value; } public bool TryGetNextValue(string key, out string value) { if (_currentIndex >= _buffer.Length) { value = null; return false; } if (!TryFindNextKeyOccurrence(key, _currentIndex, out var keyIndex)) { value = null; return false; } int startIndex = keyIndex + key.Length; int num = _buffer.IndexOf(Environment.NewLine, startIndex, _comparisonKind); int num2; if (num == -1) { num = _buffer.Length - 1; num2 = num; } else { num2 = num - 1; } int count = num - keyIndex; int num3 = _buffer.LastIndexOf('\t', num, count); if (num3 == -1) { num3 = _buffer.LastIndexOf(' ', num, count); } int num4 = num3 + 1; int num5 = num2 - num3; if (num4 <= keyIndex || num4 == -1 || num5 == 0) { value = null; return false; } value = _buffer.Substring(num4, num5); _currentIndex = num + 1; return true; } private bool TryFindNextKeyOccurrence(string key, int startIndex, out int keyIndex) { while (true) { keyIndex = _buffer.IndexOf(key, startIndex, _comparisonKind); if (keyIndex == -1) { return false; } if ((keyIndex == 0 || (keyIndex >= Environment.NewLine.Length && _buffer.Substring(keyIndex - Environment.NewLine.Length, Environment.NewLine.Length) == Environment.NewLine)) && HasFollowingWhitespace(keyIndex, key.Length)) { break; } startIndex += key.Length; } return true; } private bool HasFollowingWhitespace(int keyIndex, int length) { if (keyIndex + length < _buffer.Length) { if (_buffer[keyIndex + length] != ' ') { return _buffer[keyIndex + length] == '\t'; } return true; } return false; } public int GetNextValueAsInt32(string key) { string nextValue = GetNextValue(key); if (int.TryParse(nextValue, out var result)) { return result; } throw new InvalidOperationException("Unable to parse value " + nextValue + " of key " + key + " as an Int32."); } public static string ReadFirstValueFromString(string data, string key) { return new System.IO.RowConfigReader(data).GetNextValue(key); } } } namespace DnsClient { public class DnsDatagramReader { public const int IPv6Length = 16; public const int IPv4Length = 4; private const byte ReferenceByte = 192; private const string ACEPrefix = "xn--"; private const int MaxRecursion = 100; private readonly byte[] _ipV4Buffer = new byte[4]; private readonly byte[] _ipV6Buffer = new byte[16]; private readonly ArraySegment<byte> _data; private readonly int _count; public int Index { get; private set; } public bool DataAvailable { get { if (_count - _data.Offset > 0) { return Index < _count; } return false; } } public DnsDatagramReader(ArraySegment<byte> data, int startIndex = 0) { if (startIndex < 0 || startIndex > data.Count) { throw new ArgumentOutOfRangeException("startIndex"); } _data = data; _count = data.Count; Index = startIndex; } public string ReadStringWithLengthPrefix() { byte length = ReadByte(); return ReadString(length); } public string ReadString(int length) { if (_count < Index + length) { throw new DnsResponseParseException("Cannot read string.", _data.ToArray(), Index, length); } string @string = Encoding.ASCII.GetString(_data.Array, _data.Offset + Index, length); Index += length; return @string; } public static string ParseString(ArraySegment<byte> data) { return ParseString(new DnsDatagramReader(data), data.Count); } public static string ParseString(DnsDatagramReader reader, int length) { if (reader._count < reader.Index + length) { throw new DnsResponseParseException("Cannot parse string.", reader._data.ToArray(), reader.Index, length); } StringBuilder stringBuilder = StringBuilderObjectPool.Default.Get(); for (int i = 0; i < length; i++) { byte b = reader.ReadByte(); char c = (char)b; if (b < 32 || b > 126) { stringBuilder.Append("\\" + b.ToString("000", CultureInfo.InvariantCulture)); continue; } switch (c) { case ';': stringBuilder.Append("\\;"); break; case '\\': stringBuilder.Append("\\\\"); break; case '"': stringBuilder.Append("\\\""); break; default: stringBuilder.Append(c); break; } } string result = stringBuilder.ToString(); StringBuilderObjectPool.Default.Return(stringBuilder); return result; } public static string ReadUTF8String(ArraySegment<byte> data) { return Encoding.UTF8.GetString(data.Array, data.Offset, data.Count); } public byte ReadByte() { if (_count < Index + 1) { throw new DnsResponseParseException("Cannot read byte.", _data.ToArray(), Index, 1); } return _data.Array[_data.Offset + Index++]; } public ArraySegment<byte> ReadBytes(int length) { if (_count < Index + length) { throw new DnsResponseParseException("Cannot read bytes.", _data.ToArray(), Index, length); } ArraySegment<byte> result = new ArraySegment<byte>(_data.Array, _data.Offset + Index, length); Index += length; return result; } public ArraySegment<byte> ReadBytesToEnd(int startIndex, int lengthOfRawData) { int num = Index - startIndex; int length = lengthOfRawData - num; return ReadBytes(length); } public IPAddress ReadIPAddress() { if (_count < Index + 4) { throw new DnsResponseParseException($"Cannot read IPv4 address, expected {4} bytes.", _data.ToArray(), Index, 4); } _ipV4Buffer[0] = _data.Array[_data.Offset + Index]; _ipV4Buffer[1] = _data.Array[_data.Offset + Index + 1]; _ipV4Buffer[2] = _data.Array[_data.Offset + Index + 2]; _ipV4Buffer[3] = _data.Array[_data.Offset + Index + 3]; Advance(4); return new IPAddress(_ipV4Buffer); } public IPAddress ReadIPv6Address() { if (_count < Index + 16) { throw new DnsResponseParseException($"Cannot read IPv6 address, expected {16} bytes.", _data.ToArray(), Index, 16); } for (int i = 0; i < 16; i++) { _ipV6Buffer[i] = _data.Array[_data.Offset + Index + i]; } Advance(16); return new IPAddress(_ipV6Buffer); } public void Advance(int length) { if (_count < Index + length) { throw new DnsResponseParseException("Cannot advance the reader.", _data.ToArray(), Index, length); } Index += length; } public DnsString ReadDnsName() { StringBuilder stringBuilder = StringBuilderObjectPool.Default.Get(); StringBuilder stringBuilder2 = StringBuilderObjectPool.Default.Get(); foreach (ArraySegment<byte> item in ReadLabels()) { foreach (byte item2 in item) { char c = (char)item2; if (item2 < 32 || item2 > 126) { stringBuilder.Append("\\" + item2.ToString("000")); continue; } switch (c) { case ';': stringBuilder.Append("\\;"); break; case '\\': stringBuilder.Append("\\\\"); break; case '"': stringBuilder.Append("\\\""); break; default: stringBuilder.Append(c); break; } } stringBuilder.Append('.'); string text = Encoding.UTF8.GetString(item.Array, item.Offset, item.Count); if (text.StartsWith("xn--", StringComparison.Ordinal)) { try { text = DnsString.s_idn.GetUnicode(text); } catch { } } stringBuilder2.Append(text); stringBuilder2.Append('.'); } string text2 = stringBuilder.ToString(); if (text2.Length == 0 || text2[text2.Length - 1] != '.') { text2 += "."; } string text3 = stringBuilder2.ToString(); if (text3.Length == 0 || text3[text3.Length - 1] != '.') { text3 += "."; } StringBuilderObjectPool.Default.Return(stringBuilder); StringBuilderObjectPool.Default.Return(stringBuilder2); return new DnsString(text3, text2); } public DnsString ReadQuestionQueryString() { StringBuilder stringBuilder = StringBuilderObjectPool.Default.Get(); foreach (ArraySegment<byte> item in ReadLabels()) { string @string = Encoding.UTF8.GetString(item.Array, item.Offset, item.Count); stringBuilder.Append(@string); stringBuilder.Append('.'); } string query = stringBuilder.ToString(); StringBuilderObjectPool.Default.Return(stringBuilder); return DnsString.FromResponseQueryString(query); } public IReadOnlyList<ArraySegment<byte>> ReadLabels(int recursion = 0) { if (recursion++ >= 100) { throw new DnsResponseParseException("Max recursion reached.", _data.ToArray(), Index); } List<ArraySegment<byte>> list = new List<ArraySegment<byte>>(10); byte b; while ((b = ReadByte()) != 0) { if ((b & 0xC0u) != 0) { int num = ((b & 0x3F) << 8) | ReadByte(); if (num < _data.Array.Length - 1) { IReadOnlyList<ArraySegment<byte>> collection = new DnsDatagramReader(_data.SubArrayFromOriginal(num)).ReadLabels(recursion); list.AddRange(collection); return list; } Index--; list.Add(_data.SubArray(Index, b)); Advance(b); } else { if (Index + b >= _count) { throw new DnsResponseParseException("Found invalid label position.", _data.ToArray(), Index, b); } ArraySegment<byte> item = _data.SubArray(Index, b); list.Add(item); Advance(b); } } return list; } public ushort ReadUInt16() { if (_count < Index + 2) { throw new DnsResponseParseException("Cannot read more Int16.", _data.ToArray(), Index, 2); } ushort result = BitConverter.ToUInt16(_data.Array, _data.Offset + Index); Index += 2; return result; } public ushort ReadUInt16NetworkOrder() { if (_count < Index + 2) { throw new DnsResponseParseException("Cannot read more Int16.", _data.ToArray(), Index, 2); } return (ushort)((ReadByte() << 8) | ReadByte()); } public uint ReadUInt32NetworkOrder() { if (_count < Index + 4) { throw new DnsResponseParseException("Cannot read more Int32.", _data.ToArray(), Index, 4); } return (uint)((ReadUInt16NetworkOrder() << 16) | ReadUInt16NetworkOrder()); } internal void SanitizeResult(int expectedIndex, int dataLength) { if (Index != expectedIndex) { throw new DnsResponseParseException($"Record reader index out of sync. Expected to read till {expectedIndex} but tried to read till index {Index}.", _data.ToArray(), Index, dataLength); } } } internal static class ArraySegmentExtensions { public static ArraySegment<T> SubArray<T>(this ArraySegment<T> array, int startIndex, int length) { return new ArraySegment<T>(array.Array, array.Offset + startIndex, length); } public static ArraySegment<T> SubArrayFromOriginal<T>(this ArraySegment<T> array, int startIndex) { return new ArraySegment<T>(array.Array, startIndex, array.Array.Length - startIndex); } } internal class DnsDatagramWriter : IDisposable { public const int BufferSize = 1024; private const byte DotByte = 46; private readonly PooledBytes _pooledBytes; private readonly ArraySegment<byte> _buffer; public ArraySegment<byte> Data => new ArraySegment<byte>(_buffer.Array, 0, Index); public int Index { get; set; } public DnsDatagramWriter() { _pooledBytes = new PooledBytes(1024); _buffer = new ArraySegment<byte>(_pooledBytes.Buffer, 0, 1024); } public DnsDatagramWriter(ArraySegment<byte> useBuffer) { _buffer = useBuffer; } public virtual void WriteHostName(string queryName) { byte[] bytes = Encoding.UTF8.GetBytes(queryName); int num = 0; int num2 = 0; if (bytes.Length <= 1) { WriteByte(0); return; } byte[] array = bytes; for (int i = 0; i < array.Length; i++) { if (array[i] == 46) { WriteByte((byte)(num2 - num)); WriteBytes(bytes, num, num2 - num); num = num2 + 1; } num2++; } WriteByte(0); } public virtual void WriteStringWithLengthPrefix(string value) { byte[] bytes = Encoding.UTF8.GetBytes(value); int num = bytes.Length; if (num > 255) { throw new ArgumentException("Value is too long.", "value"); } WriteByte((byte)num); WriteBytes(bytes, num); } public virtual void WriteByte(byte b) { _buffer.Array[_buffer.Offset + Index++] = b; } public virtual void WriteBytes(byte[] data, int length) { WriteBytes(data, 0, length); } public virtual void WriteBytes(byte[] data, int dataOffset, int length) { Buffer.BlockCopy(data, dataOffset, _buffer.Array, _buffer.Offset + Index, length); Index += length; } public virtual void WriteInt16NetworkOrder(short value) { byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)); WriteBytes(bytes, bytes.Length); } public virtual void WriteInt32NetworkOrder(int value) { byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)); WriteBytes(bytes, bytes.Length); } public virtual void WriteUInt16NetworkOrder(ushort value) { WriteInt16NetworkOrder((short)value); } public virtual void WriteUInt32NetworkOrder(uint value) { WriteInt32NetworkOrder((int)value); } protected virtual void Dispose(bool disposing) { if (disposing) { _pooledBytes?.Dispose(); } } public void Dispose() { Dispose(disposing: true); } } internal enum DnsMessageHandleType { None, UDP, TCP } internal abstract class DnsMessageHandler { public abstract DnsMessageHandleType Type { get; } public abstract DnsResponseMessage Query(IPEndPoint endpoint, DnsRequestMessage request, TimeSpan timeout); public abstract Task<DnsResponseMessage> QueryAsync(IPEndPoint endpoint, DnsRequestMessage request, CancellationToken cancellationToken); public static bool IsTransientException(Exception exception) { if (exception is IOException) { exception = exception?.InnerException ?? exception; } if (exception is SocketException ex) { switch (ex.SocketErrorCode) { case SocketError.OperationAborted: case SocketError.ConnectionAborted: case SocketError.ConnectionReset: case SocketError.TimedOut: case SocketError.TryAgain: return true; } } return false; } protected static void ValidateResponse(DnsRequestMessage request, DnsResponseMessage response) { if (request == null) { throw new ArgumentNullException("request"); } if (response == null) { throw new ArgumentNullException("response"); } if (request.Header.Id != response.Header.Id) { throw new DnsXidMismatchException(request.Header.Id, response.Header.Id); } } public virtual void GetRequestData(DnsRequestMessage request, DnsDatagramWriter writer) { DnsQuestion question = request.Question; writer.WriteInt16NetworkOrder((short)request.Header.Id); writer.WriteUInt16NetworkOrder(request.Header.RawFlags); writer.WriteInt16NetworkOrder(1); writer.WriteInt16NetworkOrder(0); writer.WriteInt16NetworkOrder(0); if (request.QuerySettings.UseExtendedDns) { writer.WriteInt16NetworkOrder(1); } else { writer.WriteInt16NetworkOrder(0); } writer.WriteHostName(question.QueryName); writer.WriteUInt16NetworkOrder((ushort)question.QuestionType); writer.WriteUInt16NetworkOrder((ushort)question.QuestionClass); if (request.QuerySettings.UseExtendedDns) { OptRecord optRecord = new OptRecord(request.QuerySettings.ExtendedDnsBufferSize, 0, request.QuerySettings.RequestDnsSecRecords); writer.WriteHostName(""); writer.WriteUInt16NetworkOrder((ushort)optRecord.RecordType); writer.WriteUInt16NetworkOrder((ushort)optRecord.RecordClass); writer.WriteUInt32NetworkOrder((ushort)optRecord.InitialTimeToLive); writer.WriteUInt16NetworkOrder(0); } } public virtual DnsResponseMessage GetResponseMessage(ArraySegment<byte> responseData) { DnsDatagramReader dnsDatagramReader = new DnsDatagramReader(responseData); DnsRecordFactory dnsRecordFactory = new DnsRecordFactory(dnsDatagramReader); ushort id = dnsDatagramReader.ReadUInt16NetworkOrder(); ushort flags = dnsDatagramReader.ReadUInt16NetworkOrder(); ushort num = dnsDatagramReader.ReadUInt16NetworkOrder(); ushort num2 = dnsDatagramReader.ReadUInt16NetworkOrder(); ushort num3 = dnsDatagramReader.ReadUInt16NetworkOrder(); ushort num4 = dnsDatagramReader.ReadUInt16NetworkOrder(); DnsResponseMessage dnsResponseMessage = new DnsResponseMessage(new DnsResponseHeader(id, flags, num, num2, num4, num3), responseData.Count); for (int i = 0; i < num; i++) { DnsQuestion question = new DnsQuestion(dnsDatagramReader.ReadQuestionQueryString(), (QueryType)dnsDatagramReader.ReadUInt16NetworkOrder(), (QueryClass)dnsDatagramReader.ReadUInt16NetworkOrder()); dnsResponseMessage.AddQuestion(question); } for (int j = 0; j < num2; j++) { ResourceRecordInfo info = dnsRecordFactory.ReadRecordInfo(); DnsResourceRecord record = dnsRecordFactory.GetRecord(info); dnsResponseMessage.AddAnswer(record); } for (int k = 0; k < num3; k++) { ResourceRecordInfo info2 = dnsRecordFactory.ReadRecordInfo(); DnsResourceRecord record2 = dnsRecordFactory.GetRecord(info2); dnsResponseMessage.AddAuthority(record2); } for (int l = 0; l < num4; l++) { ResourceRecordInfo info3 = dnsRecordFactory.ReadRecordInfo(); DnsResourceRecord record3 = dnsRecordFactory.GetRecord(info3); dnsResponseMessage.AddAdditional(record3); } return dnsResponseMessage; } } public enum DnsOpCode : short { Query, [Obsolete("obsolete per RFC")] IQuery, Status, Unassinged3, Notify, Update, Unassinged6, Unassinged7, Unassinged8, Unassinged9, Unassinged10, Unassinged11, Unassinged12, Unassinged13, Unassinged14, Unassinged15 } public static class DnsQueryExtensions { public static IPHostEntry GetHostEntry(this IDnsQuery query, string hostNameOrAddress) { if (query == null) { throw new ArgumentNullException("query"); } if (string.IsNullOrWhiteSpace(hostNameOrAddress)) { throw new ArgumentNullException("hostNameOrAddress"); } if (IPAddress.TryParse(hostNameOrAddress, out IPAddress address)) { return query.GetHostEntry(address); } return GetHostEntryFromName(query, hostNameOrAddress); } public static Task<IPHostEntry> GetHostEntryAsync(this IDnsQuery query, string hostNameOrAddress) { if (query == null) { throw new ArgumentNullException("query"); } if (string.IsNullOrWhiteSpace(hostNameOrAddress)) { throw new ArgumentNullException("hostNameOrAddress"); } if (IPAddress.TryParse(hostNameOrAddress, out IPAddress address)) { return query.GetHostEntryAsync(address); } return GetHostEntryFromNameAsync(query, hostNameOrAddress); } public static IPHostEntry GetHostEntry(this IDnsQuery query, IPAddress address) { if (query == null) { throw new ArgumentNullException("query"); } if (address == null) { throw new ArgumentNullException("address"); } string hostName = query.GetHostName(address); if (string.IsNullOrWhiteSpace(hostName)) { return null; } return GetHostEntryFromName(query, hostName); } public static async Task<IPHostEntry> GetHostEntryAsync(this IDnsQuery query, IPAddress address) { if (query == null) { throw new ArgumentNullException("query"); } if (address == null) { throw new ArgumentNullException("address"); } string text = await query.GetHostNameAsync(address).ConfigureAwait(continueOnCapturedContext: false); if (string.IsNullOrWhiteSpace(text)) { return null; } return await GetHostEntryFromNameAsync(query, text).ConfigureAwait(continueOnCapturedContext: false); } private static IPHostEntry GetHostEntryFromName(IDnsQuery query, string hostName) { if (string.IsNullOrWhiteSpace(hostName)) { throw new ArgumentNullException("hostName"); } DnsString dnsString = DnsString.FromResponseQueryString(hostName); IDnsQueryResponse dnsQueryResponse = query.Query(dnsString, QueryType.A); DnsResourceRecord[] allRecords = Enumerable.Concat(second: query.Query(dnsString, QueryType.AAAA).Answers, first: dnsQueryResponse.Answers).ToArray(); return GetHostEntryProcessResult(dnsString, allRecords); } private static async Task<IPHostEntry> GetHostEntryFromNameAsync(IDnsQuery query, string hostName) { if (string.IsNullOrWhiteSpace(hostName)) { throw new ArgumentNullException("hostName"); } DnsString hostString = DnsString.FromResponseQueryString(hostName); Task<IDnsQueryResponse> ipv4Result = query.QueryAsync(hostString, QueryType.A); Task<IDnsQueryResponse> ipv6Result = query.QueryAsync(hostString, QueryType.AAAA); await Task.WhenAll<IDnsQueryResponse>(ipv4Result, ipv6Result).ConfigureAwait(continueOnCapturedContext: false); DnsResourceRecord[] allRecords = ipv4Result.Result.Answers.Concat(ipv6Result.Result.Answers).ToArray(); return GetHostEntryProcessResult(hostString, allRecords); } private static IPHostEntry GetHostEntryProcessResult(DnsString hostString, DnsResourceRecord[] allRecords) { var array = (from p in allRecords.OfType<AddressRecord>() select new { Address = p.Address, Alias = DnsString.FromResponseQueryString(p.DomainName) }).ToArray(); IPHostEntry iPHostEntry = new IPHostEntry { Aliases = new string[0], AddressList = array.Select(p => p.Address).ToArray() }; if (array.Length > 1) { if (array.Any(p => !p.Alias.Equals(hostString))) { iPHostEntry.Aliases = (from p in array select p.Alias.ToString() into p select p.Substring(0, p.Length - 1)).Distinct().ToArray(); } } else if (array.Length == 1 && allRecords.Any((DnsResourceRecord p) => !DnsString.FromResponseQueryString(p.DomainName).Equals(hostString))) { iPHostEntry.Aliases = (from p in allRecords select p.DomainName.ToString() into p select p.Substring(0, p.Length - 1)).Distinct().ToArray(); } iPHostEntry.HostName = hostString.Value.Substring(0, hostString.Value.Length - 1); return iPHostEntry; } public static string GetHostName(this IDnsQuery query, IPAddress address) { if (query == null) { throw new ArgumentNullException("query"); } if (address == null) { throw new ArgumentNullException("address"); } return GetHostNameAsyncProcessResult(query.QueryReverse(address)); } public static async Task<string> GetHostNameAsync(this IDnsQuery query, IPAddress address) { if (query == null) { throw new ArgumentNullException("query"); } if (address == null) { throw new ArgumentNullException("address"); } return GetHostNameAsyncProcessResult(await query.QueryReverseAsync(address).ConfigureAwait(continueOnCapturedContext: false)); } private static string GetHostNameAsyncProcessResult(IDnsQueryResponse result) { if (result.HasError) { return null; } DnsString dnsString = result.Answers.PtrRecords().FirstOrDefault()?.PtrDomainName; if (string.IsNullOrWhiteSpace(dnsString)) { return null; } return dnsString.Value.Substring(0, dnsString.Value.Length - 1); } public static ServiceHostEntry[] ResolveService(this IDnsQuery query, string baseDomain, string serviceName, ProtocolType protocol) { if (protocol == ProtocolType.IP || protocol == ProtocolType.Unknown) { return query.ResolveService(baseDomain, serviceName); } return query.ResolveService(baseDomain, serviceName, protocol.ToString()); } public static Task<ServiceHostEntry[]> ResolveServiceAsync(this IDnsQuery query, string baseDomain, string serviceName, ProtocolType protocol) { if (protocol == ProtocolType.IP || protocol == ProtocolType.Unknown) { return query.ResolveServiceAsync(baseDomain, serviceName); } return query.ResolveServiceAsync(baseDomain, serviceName, protocol.ToString()); } public static ServiceHostEntry[] ResolveService(this IDnsQuery query, string baseDomain, string serviceName, string tag = null) { if (query == null) { throw new ArgumentNullException("query"); } if (baseDomain == null) { throw new ArgumentNullException("baseDomain"); } if (string.IsNullOrWhiteSpace(serviceName)) { throw new ArgumentNullException("serviceName"); } string query2 = ConcatServiceName(baseDomain, serviceName, tag); return ResolveServiceProcessResult(query.Query(query2, QueryType.SRV)); } public static ServiceHostEntry[] ResolveService(this IDnsQuery query, string service) { if (query == null) { throw new ArgumentNullException("query"); } if (string.IsNullOrWhiteSpace(service)) { throw new ArgumentNullException("service"); } return ResolveServiceProcessResult(query.Query(service, QueryType.SRV)); } public static async Task<ServiceHostEntry[]> ResolveServiceAsync(this IDnsQuery query, string baseDomain, string serviceName, string tag = null) { if (query == null) { throw new ArgumentNullException("query"); } if (baseDomain == null) { throw new ArgumentNullException("baseDomain"); } if (string.IsNullOrWhiteSpace(serviceName)) { throw new ArgumentNullException("serviceName"); } string query2 = ConcatServiceName(baseDomain, serviceName, tag); return ResolveServiceProcessResult(await query.QueryAsync(query2, QueryType.SRV).ConfigureAwait(continueOnCapturedContext: false)); } public static async Task<ServiceHostEntry[]> ResolveServiceAsync(this IDnsQuery query, string service) { if (query == null) { throw new ArgumentNullException("query"); } if (string.IsNullOrWhiteSpace(service)) { throw new ArgumentNullException("service"); } return ResolveServiceProcessResult(await query.QueryAsync(service, QueryType.SRV).ConfigureAwait(continueOnCapturedContext: false)); } public static string ConcatServiceName(string baseDomain, string serviceName, string tag = null) { if (!string.IsNullOrWhiteSpace(tag)) { return "_" + serviceName + "._" + tag + "." + baseDomain + "."; } return serviceName + "." + baseDomain + "."; } public static ServiceHostEntry[] ResolveServiceProcessResult(IDnsQueryResponse result) { List<ServiceHostEntry> list = new List<ServiceHostEntry>(); if (result == null || result.HasError) { return list.ToArray(); } foreach (SrvRecord entry in result.Answers.SrvRecords()) { IEnumerable<IPAddress> source = from p in result.Additionals.OfType<AddressRecord>() where p.DomainName.Equals(entry.Target) select p.Address; DnsString dnsString = (from p in result.Additionals.OfType<CNameRecord>() where p.DomainName.Equals(entry.Target) select p.CanonicalName).FirstOrDefault() ?? entry.Target; list.Add(new ServiceHostEntry { AddressList = source.ToArray(), HostName = dnsString, Port = entry.Port, Priority = entry.Priority, Weight = entry.Weight }); } return list.ToArray(); } } public class ServiceHostEntry : IPHostEntry { public int Port { get; set; } public int Priority { get; set; } public int Weight { get; set; } } public class DnsQueryOptions { public const int MinimumBufferSize = 512; public const int MaximumBufferSize = 4096; private static readonly TimeSpan s_defaultTimeout = TimeSpan.FromSeconds(5.0); private static readonly TimeSpan s_infiniteTimeout = System.Threading.Timeout.InfiniteTimeSpan; private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(2147483647.0); private TimeSpan _timeout = s_defaultTimeout; private int _ednsBufferSize = 4096; private TimeSpan _failedResultsCacheDuration = s_defaultTimeout; public bool EnableAuditTrail { get; set; } public bool UseCache { get; set; } = true; public bool Recursion { get; set; } = true; public int Retries { get; set; } = 2; public bool ThrowDnsErrors { get; set; } public bool UseRandomNameServer { get; set; } = true; public bool ContinueOnDnsError { get; set; } = true; public bool ContinueOnEmptyResponse { get; set; } = true; public TimeSpan Timeout { get { return _timeout; } set { if ((value <= TimeSpan.Zero || value > s_maxTimeout) && value != s_infiniteTimeout) { throw new ArgumentOutOfRangeException("value"); } _timeout = value; } } public bool UseTcpFallback { get; set; } = true; public bool UseTcpOnly { get; set; } public int ExtendedDnsBufferSize { get { return _ednsBufferSize; } set { _ednsBufferSize = ((value < 512) ? 512 : ((value > 4096) ? 4096 : value)); } } public bool RequestDnsSecRecords { get; set; } public bool CacheFailedResults { get; set; } public TimeSpan FailedResultsCacheDuration { get { return _failedResultsCacheDuration; } set { if ((value <= TimeSpan.Zero || value > s_maxTimeout) && value != s_infiniteTimeout) { throw new ArgumentOutOfRangeException("value"); } _failedResultsCacheDuration = value; } } public static implicit operator DnsQuerySettings(DnsQueryOptions fromOptions) { if (fromOptions == null) { return null; } return new DnsQuerySettings(fromOptions); } } public class DnsQueryAndServerOptions : DnsQueryOptions { public IReadOnlyList<NameServer> NameServers { get; } = new NameServer[0]; public DnsQueryAndServerOptions() { } public DnsQueryAndServerOptions(params NameServer[] nameServers) { if (nameServers != null && nameServers.Length != 0) { NameServers = nameServers.ToList(); return; } throw new ArgumentNullException("nameServers"); } public DnsQueryAndServerOptions(params IPEndPoint[] nameServers) : this(nameServers?.Select((Func<IPEndPoint, NameServer>)((IPEndPoint p) => p)).ToArray()) { } public DnsQueryAndServerOptions(params IPAddress[] nameServers) : this(nameServers?.Select((Func<IPAddress, NameServer>)((IPAddress p) => p)).ToArray()) { } public static implicit operator DnsQueryAndServerSettings(DnsQueryAndServerOptions fromOptions) { if (fromOptions == null) { return null; } return new DnsQueryAndServerSettings(fromOptions); } } public class LookupClientOptions : DnsQueryAndServerOptions { private static readonly TimeSpan s_infiniteTimeout = System.Threading.Timeout.InfiniteTimeSpan; private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(2147483647.0); private TimeSpan? _minimumCacheTimeout; private TimeSpan? _maximumCacheTimeout; public bool AutoResolveNameServers { get; set; } = true; public TimeSpan? MinimumCacheTimeout { get { return _minimumCacheTimeout; } set { if (value.HasValue && (value < TimeSpan.Zero || value > s_maxTimeout) && value != s_infiniteTimeout) { throw new ArgumentOutOfRangeException("value"); } if (value == TimeSpan.Zero) { _minimumCacheTimeout = null; } else { _minimumCacheTimeout = value; } } } public TimeSpan? MaximumCacheTimeout { get { return _maximumCacheTimeout; } set { if (value.HasValue && (value < TimeSpan.Zero || value > s_maxTimeout) && value != s_infiniteTimeout) { throw new ArgumentOutOfRangeException("value"); } if (value == TimeSpan.Zero) { _maximumCacheTimeout = null; } else { _maximumCacheTimeout = value; } } } public LookupClientOptions() { } public LookupClientOptions(params NameServer[] nameServers) : base(nameServers) { AutoResolveNameServers = false; } public LookupClientOptions(params IPEndPoint[] nameServers) : base(nameServers) { AutoResolveNameServers = false; } public LookupClientOptions(params IPAddress[] nameServers) : base(nameServers) { AutoResolveNameServers = false; } } public class DnsQuerySettings : IEquatable<DnsQuerySettings> { public bool EnableAuditTrail { get; } public bool UseCache { get; } public bool Recursion { get; } public int Retries { get; } public bool ThrowDnsErrors { get; } public bool UseRandomNameServer { get; } public bool ContinueOnDnsError { get; } public bool ContinueOnEmptyResponse { get; } public TimeSpan Timeout { get; } public bool UseTcpFallback { get; } public bool UseTcpOnly { get; } public bool UseExtendedDns { get { if (ExtendedDnsBufferSize <= 512) { return RequestDnsSecRecords; } return true; } } public int ExtendedDnsBufferSize { get; } public bool RequestDnsSecRecords { get; } public bool CacheFailedResults { get; } public TimeSpan FailedResultsCacheDuration { get; } public DnsQuerySettings(DnsQueryOptions options) { if (options == null) { throw new ArgumentNullException("options"); } ContinueOnDnsError = options.ContinueOnDnsError; ContinueOnEmptyResponse = options.ContinueOnEmptyResponse; EnableAuditTrail = options.EnableAuditTrail; Recursion = options.Recursion; Retries = options.Retries; ThrowDnsErrors = options.ThrowDnsErrors; Timeout = options.Timeout; UseCache = options.UseCache; UseRandomNameServer = options.UseRandomNameServer; UseTcpFallback = options.UseTcpFallback; UseTcpOnly = options.UseTcpOnly; ExtendedDnsBufferSize = options.ExtendedDnsBufferSize; RequestDnsSecRecords = options.RequestDnsSecRecords; CacheFailedResults = options.CacheFailedResults; FailedResultsCacheDuration = options.FailedResultsCacheDuration; } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } return Equals(obj as DnsQuerySettings); } public bool Equals(DnsQuerySettings other) { if (other == null) { return false; } if (this == other) { return true; } if (EnableAuditTrail == other.EnableAuditTrail && UseCache == other.UseCache && Recursion == other.Recursion && Retries == other.Retries && ThrowDnsErrors == other.ThrowDnsErrors && UseRandomNameServer == other.UseRandomNameServer && ContinueOnDnsError == other.ContinueOnDnsError && ContinueOnEmptyResponse == other.ContinueOnEmptyResponse && Timeout.Equals(other.Timeout) && UseTcpFallback == other.UseTcpFallback && UseTcpOnly == other.UseTcpOnly && ExtendedDnsBufferSize == other.ExtendedDnsBufferSize && RequestDnsSecRecords == other.RequestDnsSecRecords && CacheFailedResults == other.CacheFailedResults) { return FailedResultsCacheDuration.Equals(other.FailedResultsCacheDuration); } return false; } } public class DnsQueryAndServerSettings : DnsQuerySettings, IEquatable<DnsQueryAndServerSettings> { private readonly NameServer[] _endpoints; private readonly Random _rnd = new Random(); public IReadOnlyList<NameServer> NameServers => _endpoints; public DnsQueryAndServerSettings(DnsQueryAndServerOptions options) : base(options) { _endpoints = options.NameServers?.ToArray() ?? new NameServer[0]; } public DnsQueryAndServerSettings(DnsQueryAndServerOptions options, IReadOnlyCollection<NameServer> overrideServers) : this(options) { _endpoints = overrideServers?.ToArray() ?? throw new ArgumentNullException("overrideServers"); } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } return Equals(obj as DnsQueryAndServerSettings); } public bool Equals(DnsQueryAndServerSettings other) { if (other == null) { return false; } if (this == other) { return true; } if (NameServers.SequenceEqual(other.NameServers)) { return Equals((DnsQuerySettings)other); } return false; } internal IReadOnlyList<NameServer> ShuffleNameServers() { if (_endpoints.Length > 1 && base.UseRandomNameServer) { NameServer[] array = _endpoints.ToArray(); for (int num = array.Length; num > 0; num--) { int num2 = _rnd.Next(0, num); NameServer nameServer = array[num2]; array[num2] = array[num - 1]; array[num - 1] = nameServer; } return array; } return NameServers; } } public class LookupClientSettings : DnsQueryAndServerSettings, IEquatable<LookupClientSettings> { public TimeSpan? MinimumCacheTimeout { get; } public TimeSpan? MaximumCacheTimeout { get; } public LookupClientSettings(LookupClientOptions options) : base(options) { MinimumCacheTimeout = options.MinimumCacheTimeout; MaximumCacheTimeout = options.MaximumCacheTimeout; } internal LookupClientSettings(LookupClientOptions options, IReadOnlyCollection<NameServer> overrideServers) : base(options, overrideServers) { MinimumCacheTimeout = options.MinimumCacheTimeout; MaximumCacheTimeout = options.MaximumCacheTimeout; } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } return Equals(obj as LookupClientSettings); } public bool Equals(LookupClientSettings other) { if (other == null) { return false; } if (this == other) { return true; } if (object.Equals(MinimumCacheTimeout, other.MinimumCacheTimeout) && object.Equals(MaximumCacheTimeout, other.MaximumCacheTimeout)) { return Equals((DnsQueryAndServerSettings)other); } return false; } } internal class TruncatedQueryResponse : IDnsQueryResponse { public IReadOnlyList<DnsQuestion> Questions { get { throw new NotImplementedException(); } } public IReadOnlyList<DnsResourceRecord> Additionals { get { throw new NotImplementedException(); } } public IEnumerable<DnsResourceRecord> AllRecords { get { throw new NotImplementedException(); } } public IReadOnlyList<DnsResourceRecord> Answers { get { throw new NotImplementedException(); } } public IReadOnlyList<DnsResourceRecord> Authorities { get { throw new NotImplementedException(); } } public string AuditTrail { get { throw new NotImplementedException(); } } public string ErrorMessage { get { throw new NotImplementedException(); } } public bool HasError { get { throw new NotImplementedException(); } } public DnsResponseHeader Header { get { throw new NotImplementedException(); } } public int MessageSize { get { throw new NotImplementedException(); } } public NameServer NameServer { get { throw new NotImplementedException(); } } public DnsQuerySettings Settings { get { throw new NotImplementedException(); } } } public class DnsQueryResponse : IDnsQueryResponse { private int? _hashCode; public NameServer NameServer { get; } public IReadOnlyList<DnsResourceRecord> Additionals { get; } public IEnumerable<DnsResourceRecord> AllRecords => Answers.Concat(Additionals).Concat(Authorities); public string AuditTrail { get; private set; } public IReadOnlyList<DnsResourceRecord> Answers { get; } public IReadOnlyList<DnsResourceRecord> Authorities { get; } public string ErrorMessage => DnsResponseCodeText.GetErrorText((DnsResponseCode)Header.ResponseCode); public bool HasError { get { DnsResponseHeader header = Header; if (header == null) { return true; } return header.ResponseCode != DnsHeaderResponseCode.NoError; } } public DnsResponseHeader Header { get; } public IReadOnlyList<DnsQuestion> Questions { get; } public int MessageSize { get; } public DnsQuerySettings Settings { get; } internal DnsQueryResponse(DnsResponseMessage dnsResponseMessage, NameServer nameServer, DnsQuerySettings settings) { if (dnsResponseMessage == null) { throw new ArgumentNullException("dnsResponseMessage"); } Header = dnsResponseMessage.Header; MessageSize = dnsResponseMessage.MessageSize; Questions = dnsResponseMessage.Questions.ToArray(); Answers = dnsResponseMessage.Answers.ToArray(); Additionals = dnsResponseMessage.Additionals.ToArray(); Authorities = dnsResponseMessage.Authorities.ToArray(); NameServer = nameServer ?? throw new ArgumentNullException("nameServer"); Settings = settings; } public override bool Equals(object obj) { if (obj == null) { return false; } if (!(obj is DnsQueryResponse dnsQueryResponse)) { return false; } if (Header.ToString().Equals(dnsQueryResponse.Header.ToString(), StringComparison.OrdinalIgnoreCase) && string.Join("", Questions).Equals(string.Join("", dnsQueryResponse.Questions), StringComparison.OrdinalIgnoreCase)) { return string.Join("", AllRecords).Equals(string.Join("", dnsQueryResponse.AllRecords), StringComparison.OrdinalIgnoreCase); } return false; } public override int GetHashCode() { if (!_hashCode.HasValue) { string text = Header.ToString() + string.Join("", Questions) + string.Join("", AllRecords); _hashCode = text.GetHashCode(StringComparison.Ordinal); } return _hashCode.Value; } internal static void SetAuditTrail(IDnsQueryResponse response, string value) { if (response is DnsQueryResponse dnsQueryResponse) { dnsQueryResponse.AuditTrail = value; } } } public class DnsQuestion { public DnsString QueryName { get; } public QueryClass QuestionClass { get; } public QueryType QuestionType { get; } public DnsQuestion(string query, QueryType questionType, QueryClass questionClass = QueryClass.IN) : this(DnsString.Parse(query), questionType, questionClass) { } public DnsQuestion(DnsString query, QueryType questionType, QueryClass questionClass = QueryClass.IN) { QueryName = query ?? throw new ArgumentNullException("query"); QuestionType = questionType; QuestionClass = questionClass; } public override string ToString() { return ToString(0); } public string ToString(int offset = -32) { string text = ((offset == 0) ? string.Empty : "\t"); return string.Format("{0," + offset + "} {1}{2} {1}{3}", QueryName.Original, text, QuestionClass, QuestionType); } } internal class DnsRecordFactory { private readonly DnsDatagramReader _reader; public DnsRecordFactory(DnsDatagramReader reader) { _reader = reader ?? throw new ArgumentNullException("reader"); } public ResourceRecordInfo ReadRecordInfo() { return new ResourceRecordInfo(_reader.ReadQuestionQueryString(), (ResourceRecordType)_reader.ReadUInt16NetworkOrder(), (QueryClass)_reader.ReadUInt16NetworkOrder(), (int)_reader.ReadUInt32NetworkOrder(), _reader.ReadUInt16NetworkOrder()); } public DnsResourceRecord GetRecord(ResourceRecordInfo info) { if (info == null) { throw new ArgumentNullException("info"); } int index = _reader.Index; DnsResourceRecord result = info.RecordType switch { ResourceRecordType.A => new ARecord(info, _reader.ReadIPAddress()), ResourceRecordType.NS => new NsRecord(info, _reader.ReadDnsName()), ResourceRecordType.CNAME => new CNameRecord(info, _reader.ReadDnsName()), ResourceRecordType.SOA => ResolveSoaRecord(info), ResourceRecordType.MB => new MbRecord(info, _reader.ReadDnsName()), ResourceRecordType.MG => new MgRecord(info, _reader.ReadDnsName()), ResourceRecordType.MR => new MrRecord(info, _reader.ReadDnsName()), ResourceRecordType.NULL => new NullRecord(info, _reader.ReadBytes(info.RawDataLength).ToArray()), ResourceRecordType.WKS => ResolveWksRecord(info), ResourceRecordType.PTR => new PtrRecord(info, _reader.ReadDnsName()), ResourceRecordType.HINFO => new HInfoRecord(info, _reader.ReadStringWithLengthPrefix(), _reader.ReadStringWithLengthPrefix()), ResourceRecordType.MINFO => new MInfoRecord(info, _reader.ReadDnsName(), _reader.ReadDnsName()), ResourceRecordType.MX => ResolveMXRecord(info), ResourceRecordType.TXT => ResolveTxtRecord(info), ResourceRecordType.RP => new RpRecord(info, _reader.ReadDnsName(), _reader.ReadDnsName()), ResourceRecordType.AFSDB => new AfsDbRecord(info, (AfsType)_reader.ReadUInt16NetworkOrder(), _reader.ReadDnsName()), ResourceRecordType.AAAA => new AaaaRecord(info, _reader.ReadIPv6Address()), ResourceRecordType.SRV => ResolveSrvRecord(info), ResourceRecordType.NAPTR => ResolveNaptrRecord(info), ResourceRecordType.OPT => ResolveOptRecord(info), ResourceRecordType.DS => ResolveDsRecord(info), ResourceRecordType.SSHFP => ResolveSshfpRecord(info), ResourceRecordType.RRSIG => ResolveRRSigRecord(info), ResourceRecordType.NSEC => ResolveNSecRecord(info), ResourceRecordType.DNSKEY => ResolveDnsKeyRecord(info), ResourceRecordType.NSEC3 => ResolveNSec3Record(info), ResourceRecordType.NSEC3PARAM => ResolveNSec3ParamRecord(info), ResourceRecordType.TLSA => ResolveTlsaRecord(info), ResourceRecordType.SPF => ResolveTxtRecord(info), ResourceRecordType.URI => ResolveUriRecord(info), ResourceRecordType.CAA => ResolveCaaRecord(info), _ => new UnknownRecord(info, _reader.ReadBytes(info.RawDataLength).ToArray()), }; _reader.SanitizeResult(index + info.RawDataLength, info.RawDataLength); return result; } private DnsResourceRecord ResolveSoaRecord(ResourceRecordInfo info) { DnsString mName = _reader.ReadDnsName(); DnsString rName = _reader.ReadDnsName(); uint serial = _reader.ReadUInt32NetworkOrder(); uint refresh = _reader.ReadUInt32NetworkOrder(); uint retry = _reader.ReadUInt32NetworkOrder(); uint expire = _reader.ReadUInt32NetworkOrder(); uint minimum = _reader.ReadUInt32NetworkOrder(); return new SoaRecord(info, mName, rName, serial, refresh, retry, expire, minimum); } private DnsResourceRecord ResolveWksRecord(ResourceRecordInfo info) { IPAddress address = _reader.ReadIPAddress(); byte protocol = _reader.ReadByte(); return new WksRecord(info, address, protocol, _reader.ReadBytes(info.RawDataLength - 5).ToArray()); } private DnsResourceRecord ResolveMXRecord(ResourceRecordInfo info) { ushort preference = _reader.ReadUInt16NetworkOrder(); DnsString domainName = _reader.ReadDnsName(); return new MxRecord(info, preference, domainName); } private DnsResourceRecord ResolveTxtRecord(ResourceRecordInfo info) { int index = _reader.Index; List<string> list = new List<string>(); List<string> list2 = new List<string>(); while (_reader.Index - index < info.RawDataLength) { byte length = _reader.ReadByte(); ArraySegment<byte> data = _reader.ReadBytes(length); string item = DnsDatagramReader.ParseString(data); string item2 = DnsDatagramReader.ReadUTF8String(data); list.Add(item); list2.Add(item2); } return new TxtRecord(info, list.ToArray(), list2.ToArray()); } private DnsResourceRecord ResolveSrvRecord(ResourceRecordInfo info) { ushort priority = _reader.ReadUInt16NetworkOrder(); ushort weight = _reader.ReadUInt16NetworkOrder(); ushort port = _reader.ReadUInt16NetworkOrder(); DnsString target = _reader.ReadDnsName(); return new SrvRecord(info, priority, weight, port, target); } private DnsResourceRecord ResolveNaptrRecord(ResourceRecordInfo info) { ushort order = _reader.ReadUInt16NetworkOrder(); ushort preference = _reader.ReadUInt16NetworkOrder(); string flags = _reader.ReadStringWithLengthPrefix(); string services = _reader.ReadStringWithLengthPrefix(); string regexp = _reader.ReadStringWithLengthPrefix(); DnsString replacement = _reader.ReadDnsName(); return new NAPtrRecord(info, order, preference, flags, services, regexp, replacement); } private DnsResourceRecord ResolveOptRecord(ResourceRecordInfo info) { byte[] data = _reader.ReadBytes(info.RawDataLength).ToArray(); return new OptRecord((int)info.RecordClass, info.InitialTimeToLive, info.RawDataLength, data); } private DnsResourceRecord ResolveDsRecord(ResourceRecordInfo info) { int index = _reader.Index; ushort keyTag = _reader.ReadUInt16NetworkOrder(); byte algorithm = _reader.ReadByte(); byte digestType = _reader.ReadByte(); byte[] digest = _reader.ReadBytesToEnd(index, info.RawDataLength).ToArray(); return new DsRecord(info, keyTag, algorithm, digestType, digest); } private DnsResourceRecord ResolveSshfpRecord(ResourceRecordInfo info) { SshfpAlgorithm algorithm = (SshfpAlgorithm)_reader.ReadByte(); SshfpFingerprintType fingerprintType = (SshfpFingerprintType)_reader.ReadByte(); byte[] source = _reader.ReadBytes(info.RawDataLength - 2).ToArray(); string fingerprint = string.Join(string.Empty, source.Select((byte b) => b.ToString("X2"))); return new SshfpRecord(info, algorithm, fingerprintType, fingerprint); } private DnsResourceRecord ResolveRRSigRecord(ResourceRecordInfo info) { int index = _reader.Index; ushort coveredType = _reader.ReadUInt16NetworkOrder(); byte algorithm = _reader.ReadByte(); byte labels = _reader.ReadByte(); uint num = _reader.ReadUInt32NetworkOrder(); uint num2 = _reader.ReadUInt32NetworkOrder(); uint num3 = _reader.ReadUInt32NetworkOrder(); ushort keyTag = _reader.ReadUInt16NetworkOrder(); DnsString signersName = _reader.ReadDnsName(); byte[] signature = _reader.ReadBytesToEnd(index, info.RawDataLength).ToArray(); return new RRSigRecord(info, coveredType, algorithm, labels, num, num2, num3, keyTag, signersName, signature); } private DnsResourceRecord ResolveNSecRecord(ResourceRecordInfo info) { int index = _reader.Index; DnsString nextDomainName = _reader.ReadDnsName(); byte[] typeBitMaps = _reader.ReadBytesToEnd(index, info.RawDataLength).ToArray(); return new NSecRecord(info, nextDomainName, typeBitMaps); } private DnsResourceRecord ResolveNSec3Record(ResourceRecordInfo info) { int index = _reader.Index; byte hashAlgorithm = _reader.ReadByte(); byte flags = _reader.ReadByte(); ushort iterations = _reader.ReadUInt16NetworkOrder(); byte length = _reader.ReadByte(); byte[] salt = _reader.ReadBytes(length).ToArray(); byte length2 = _reader.ReadByte(); byte[] nextOwnersName = _reader.ReadBytes(length2).ToArray(); byte[] bitmap = _reader.ReadBytesToEnd(index, info.RawDataLength).ToArray(); return new NSec3Record(info, hashAlgorithm, flags, iterations, salt, nextOwnersName, bitmap); } private DnsResourceRecord ResolveNSec3ParamRecord(ResourceRecordInfo info) { byte hashAlgorithm = _reader.ReadByte(); byte flags = _reader.ReadByte(); ushort iterations = _reader.ReadUInt16NetworkOrder(); byte length = _reader.ReadByte(); byte[] salt = _reader.ReadBytes(length).ToArray(); return new NSec3ParamRecord(info, hashAlgorithm, flags, iterations, salt); } private DnsResourceRecord ResolveDnsKeyRecord(ResourceRecordInfo info) { int index = _reader.Index; int flags = _reader.ReadUInt16NetworkOrder(); byte protocol = _reader.ReadByte(); byte algorithm = _reader.ReadByte(); byte[] publicKey = _reader.ReadBytesToEnd(index, info.RawDataLength).ToArray(); return new DnsKeyRecord(info, flags, protocol, algorithm, publicKey); } private DnsResourceRecord ResolveTlsaRecord(ResourceRecordInfo info) { int index = _reader.Index; byte certificateUsage = _reader.ReadByte(); byte selector = _reader.ReadByte(); byte matchingType = _reader.ReadByte(); byte[] certificateAssociationData = _reader.ReadBytesToEnd(index, info.RawDataLength).ToArray(); return new TlsaRecord(info, certificateUsage, selector, matchingType, certificateAssociationData); } private DnsResourceRecord ResolveUriRecord(ResourceRecordInfo info) { ushort priority = _reader.ReadUInt16NetworkOrder(); ushort weight = _reader.ReadUInt16NetworkOrder(); string target = _reader.ReadString(info.RawDataLength - 4); return new UriRecord(info, priority, weight, target); } private DnsResourceRecord ResolveCaaRecord(ResourceRecordInfo info) { byte flags = _reader.ReadByte(); string text = _reader.ReadStringWithLengthPrefix(); string value = DnsDatagramReader.ParseString(_reader, info.RawDataLength - 2 - text.Length); return new CaaRecord(info, flags, text, value); } } internal class DnsRequestHeader { private static readonly Random s_random = new Random(); public const int HeaderLength = 12; private ushort _flags; public ushort RawFlags => _flags; internal DnsHeaderFlag HeaderFlags { get { return (DnsHeaderFlag)_flags; } set { _flags &= 65519; _flags &= 65503; _flags &= 65471; _flags &= 32767; _flags &= 64511; _flags &= 65023; _flags &= 65279; _flags &= 65407; _flags |= (ushort)value; } } public int Id { get; private set; } public DnsOpCode OpCode { get { return (DnsOpCode)((DnsHeader.OPCodeMask & _flags) >> (int)DnsHeader.OPCodeShift); } set { _flags &= (ushort)(~DnsHeader.OPCodeMask); _flags |= (ushort)(((ushort)value << (int)DnsHeader.OPCodeShift) & DnsHeader.OPCodeMask); } } public ushort RCode { get { return (ushort)(DnsHeader.RCodeMask & _flags); } set { _flags &= (ushort)(~DnsHeader.RCodeMask); _flags |= (ushort)(value & DnsHeader.RCodeMask); } } public bool UseRecursion { get { return HeaderFlags.HasFlag(DnsHeaderFlag.RecursionDesired); } set { if (value) { _flags |= 256; } else { _flags &= 65279; } } } public DnsRequestHeader(DnsOpCode queryKind) : this(useRecursion: true, queryKind) { } public DnsRequestHeader(bool useRecursion, DnsOpCode queryKind) { Id = GetNextUniqueId(); OpCode = queryKind; UseRecursion = useRecursion; } public override string ToString() { return $"{Id} - Qs: {1} Recursion: {UseRecursion} OpCode: {OpCode}"; } public void RefreshId() { Id = GetNextUniqueId(); } private static ushort GetNextUniqueId() { return (ushort)s_random.Next(1, 65535); } } [DebuggerDisplay("Request:{Header} => {Question}")] internal class DnsRequestMessage { public DnsRequestHeader Header { get; } public DnsQuestion Question { get; } public DnsQuerySettings QuerySettings { get; } public DnsRequestMessage(DnsRequestHeader header, DnsQuestion question, DnsQuerySettings dnsQuerySettings = null) { Header = header ?? throw new ArgumentNullException("header"); Question = question ?? throw new ArgumentNullException("question"); QuerySettings = dnsQuerySettings ?? new DnsQuerySettings(new DnsQueryOptions()); } public override string ToString() { return $"{Header} => {Question}"; } } public enum DnsHeaderResponseCode : short { NoError, FormatError, ServerFailure, NotExistentDomain, NotImplemented, Refused, ExistingDomain, ExistingResourceRecordSet, MissingResourceRecordSet, NotAuthorized, NotZone, Unassinged11, Unassinged12, Unassinged13, Unassinged14, Unassinged15 } public enum DnsResponseCode { NoError = 0, FormatError = 1, ServerFailure = 2, NotExistentDomain = 3, NotImplemented = 4, Refused = 5, ExistingDomain = 6, ExistingResourceRecordSet = 7, MissingResourceRecordSet = 8, NotAuthorized = 9, NotZone = 10, Unassinged11 = 11, Unassinged12 = 12, Unassinged13 = 13, Unassinged14 = 14, Unassinged15 = 15, BadVersionOrBadSignature = 16, BadKey = 17, BadTime = 18, BadMode = 19, BadName = 20, BadAlgorithm = 21, BadTruncation = 22, BadCookie = 23, Unassigned = 666, ConnectionTimeout = 999 } [Serializable] public class DnsResponseException : Exception { public DnsResponseCode Code { get; } public string AuditTrail { get; internal set; } public string DnsError { get; } public DnsResponseException() : base("Unknown Error") { Code = DnsResponseCode.Unassigned; DnsError = DnsResponseCodeText.GetErrorText(Code); } public DnsResponseException(string message) : base(message) { Code = DnsResponseCode.Unassigned; DnsError = DnsResponseCodeText.GetErrorText(Code); } public DnsResponseException(DnsResponseCode code) : base(DnsResponseCodeText.GetErrorText(code)) { Code = code; DnsError = DnsResponseCodeText.GetErrorText(Code); } public DnsResponseException(string message, Exception innerException) : base(message, innerException) { Code = DnsResponseCode.Unassigned; DnsError = DnsResponseCodeText.GetErrorText(Code); } public DnsResponseException(DnsResponseCode code, string message) : base(message) { Code = code; DnsError = DnsResponseCodeText.GetErrorText(Code); } public DnsResponseException(DnsResponseCode code, string message, Exception innerException) : base(message, innerException) { Code = code; DnsError = DnsResponseCodeText.GetErrorText(Code); } } internal static class DnsResponseCodeText { internal const string BADALG = "Algorithm not supported"; internal const string BADCOOKIE = "Bad/missing Server Cookie"; internal const string BADKEY = "Key not recognized"; internal const string BADMODE = "Bad TKEY Mode"; internal const string BADNAME = "Duplicate key name"; internal const string BADSIG = "TSIG Signature Failure"; internal const string BADTIME = "Signature out of time window"; internal const string BADTRUNC = "Bad Truncation"; internal const string BADVERS = "Bad OPT Version"; internal const string FormErr = "Format Error"; internal const string NoError = "No Error"; internal const string NotAuth = "Server Not Authoritative for zone or Not Authorized"; internal const string NotImp = "Not Implemented"; internal const string NotZone = "Name not contained in zone"; internal const string NXDomain = "Non-Existent Domain"; internal const string NXRRSet = "RR Set that should exist does not"; internal const string Refused = "Query Refused"; internal const string ServFail = "Server Failure"; internal const string Unassigned = "Unknown Error"; internal const string YXDomain = "Name Exists when it should not"; internal const string YXRRSet = "RR Set Exists when it should not"; private static readonly Dictionary<DnsResponseCode, string> s_errors = new Dictionary<DnsResponseCode, string> { { DnsResponseCode.NoError, "No Error" }, { DnsResponseCode.FormatError, "Format Error" }, { DnsResponseCode.ServerFailure, "Server Failure" }, { DnsResponseCode.NotExistentDomain, "Non-Existent Domain" }, { DnsResponseCode.NotImplemented, "Not Implemented" }, { DnsResponseCode.Refused, "Query Refused" }, { DnsResponseCode.ExistingDomain, "Name Exists when it should not" }, { DnsResponseCode.ExistingResourceRecordSet, "RR Set Exists when it should not" }, { DnsResponseCode.MissingResourceRecordSet, "RR Set that should exist does not" }, { DnsResponseCode.NotAuthorized, "Server Not Authoritative for zone or Not Authorized" }, { DnsResponseCode.NotZone, "Name not contained in zone" }, { DnsResponseCode.BadVersionOrBadSignature, "Bad OPT Version" }, { DnsResponseCode.BadKey, "Key not recognized" }, { DnsResponseCode.BadTime, "Signature out of time window" }, { DnsResponseCode.BadMode, "Bad TKEY Mode" }, { DnsResponseCode.BadName, "Duplicate key name" }, { DnsResponseCode.BadAlgorithm, "Algorithm not supported" }, { DnsResponseCode.BadTruncation, "Bad Truncation" }, { DnsResponseCode.BadCookie, "Bad/missing Server Cookie" } }; public static string GetErrorText(DnsResponseCode code) { if (!s_errors.ContainsKey(code)) { return "Unknown Error"; } return s_errors[code]; } } public class DnsResponseHeader { private readonly ushort _flags; public int AdditionalCount { get; } public int AnswerCount { get; } public bool FutureUse => HasFlag(DnsHeaderFlag.FutureUse); public bool HasAuthorityAnswer => HasFlag(DnsHeaderFlag.HasAuthorityAnswer); internal DnsHeaderFlag HeaderFlags => (DnsHeaderFlag)_flags; public int Id { get; } public bool IsAuthenticData => HasFlag(DnsHeaderFlag.IsAuthenticData); public bool IsCheckingDisabled => HasFlag(DnsHeaderFlag.IsCheckingDisabled); public bool HasQuery => HasFlag(DnsHeaderFlag.HasQuery); public int NameServerCount { get; } public DnsOpCode OPCode => (DnsOpCode)((DnsHeader.OPCodeMask & _flags) >> (int)DnsHeader.OPCodeShift); public int QuestionCount { get; } public bool RecursionAvailable => HasFlag(DnsHeaderFlag.RecursionAvailable); public DnsHeaderResponseCode ResponseCode => (DnsHeaderResponseCode)(_flags & DnsHeader.RCodeMask); public bool ResultTruncated => HasFlag(DnsHeaderFlag.ResultTruncated); public bool RecursionDesired => HasFlag(DnsHeaderFlag.RecursionDesired); [CLSCompliant(false)] public DnsResponseHeader(int id, ushort flags, int questionCount, int answerCount, int additionalCount, int serverCount) { Id = id; _flags = flags; QuestionCount = questionCount; AnswerCount = answerCount; AdditionalCount = additionalCount; NameServerCount = serverCount; } private bool HasFlag(DnsHeaderFlag flag) { return (HeaderFlags & flag) != 0; } public override string ToString() { string arg = $";; ->>HEADER<<- opcode: {OPCode}, status: {DnsResponseCodeText.GetErrorText((DnsResponseCode)ResponseCode)}, id: {Id}"; string[] source = new string[7] { HasQuery ? "qr" : "", HasAuthorityAnswer ? "aa" : "", RecursionDesired ? "rd" : "", RecursionAvailable ? "ra" : "", ResultTruncated ? "tc" : "", IsCheckingDisabled ? "cd" : "", IsAuthenticData ? "ad" : "" }; string arg2 = string.Join(" ", source.Where((string p) => p != "")); return $"{arg}\r\n;; flags: {arg2}; QUERY: {QuestionCount}, " + $"ANSWER: {AnswerCount}, AUTHORITY: {NameServerCount}, ADDITIONAL: {AdditionalCount}"; } } internal class DnsResponseMessage { public List<DnsResourceRecord> Additionals { get; } = new List<DnsResourceRecord>(); public List<DnsResourceRecord> Answers { get; } = new List<DnsResourceRecord>(); public List<DnsResourceRecord> Authorities { get; } = new List<DnsResourceRecord>(); public DnsResponseHeader Header { get; } public int MessageSize { get; } public List<DnsQuestion> Questions { get; } = new List<DnsQuestion>(); public DnsResponseMessage(DnsResponseHeader header, int messageSize) { Header = header ?? throw new ArgumentNullException("header"); MessageSize = messageSize; } public void AddAdditional(DnsResourceRecord record) { if (record == null) { throw new ArgumentNullException("record"); } Additionals.Add(record); } public void AddAnswer(DnsResourceRecord record) { if (record == null) { throw new ArgumentNullException("record"); } Answers.Add(record); } public void AddAuthority(DnsResourceRecord record) { if (record == null) { throw new ArgumentNullException("record"); } Authorities.Add(record); } public void AddQuestion(DnsQuestion question) { if (question == null) { throw new ArgumentNullException("question"); } Questions.Add(question); } public DnsQueryResponse AsQueryResponse(NameServer nameServer, DnsQuerySettings settings) { return new DnsQueryResponse(this, nameServer, settings); } public static DnsResponseMessage Combine(List<DnsResponseMessage> messages) { if (messages.Count <= 1) { return messages.FirstOrDefault(); } DnsResponseMessage dnsResponseMessage = messages[0]; DnsResponseMessage dnsResponseMessage2 = new DnsResponseMessage(new DnsResponseHeader(dnsResponseMessage.Header.Id, (ushort)dnsResponseMessage.Header.HeaderFlags, dnsResponseMessage.Header.QuestionCount, messages.Sum((DnsResponseMessage p) => p.Header.AnswerCount), messages.Sum((DnsResponseMessage p) => p.Header.AdditionalCount), dnsResponseMessage.Header.NameServerCount), messages.Sum((DnsResponseMessage p) => p.MessageSize)); dnsResponseMessage2.Questions.AddRange(dnsResponseMessage.Questions); dnsResponseMessage2.Additionals.AddRange(messages.SelectMany((DnsResponseMessage p) => p.Additionals)); dnsResponseMessage2.Answers.AddRange(messages.SelectMany((DnsResponseMessage p) => p.Answers)); dnsResponseMessage2.Authorities.AddRange(messages.SelectMany((DnsResponseMessage p) => p.Authorities)); return dnsResponseMessage2; } } [Serializable] public class DnsResponseParseException : Exception { private static readonly Func<int, int, int, string, string, string> s_defaultMessage = (int dataLength, int index, int length, string message, string dataDump) => string.Format(CultureInfo.InvariantCulture, "Response parser error, {1} bytes available, tried to read {2} bytes at index {3}.{0}{4}{0}[{5}].", Environment.NewLine, dataLength, length, index, message, dataDump); public byte[] ResponseData { get; } public int Index { get; } public int ReadLength { get; } public DnsResponseParseException() { } public DnsResponseParseException(string message) : base(message) { } public DnsResponseParseException(string message, Exception innerException) : base(message, innerException) { } public DnsResponseParseException(string message, byte[] data, int index = 0, int length = 0, Exception innerException = null) : this(s_defaultMessage(data.Length, index, length, message, FormatData(data, index, length)), innerException) { ResponseData = data ?? throw new ArgumentNullException("data"); Index = index; ReadLength = length; } private static string FormatData(byte[] data, int index, int length) { if (data == null || data.Length == 0) { return string.Empty; } return Convert.ToBase64String(data.Take(index + length + 100).ToArray()); } } public class DnsString { public const string ACEPrefix = "xn--"; public const int LabelMaxLength = 63; public const int QueryMaxLength = 255; public static readonly DnsString RootLabel = new DnsString(".", "."); internal static readonly IdnMapping s_idn = new IdnMapping(); internal const char Dot = '.'; internal const string DotStr = "."; public string Original { get; } public string Value { get; } public int? NumberOfLabels { get; } internal DnsString(string original, string value, int? numLabels = null) { Original = original; Value = value; NumberOfLabels = numLabels; } public static implicit operator string(DnsString name) { return name?.Value; } public static DnsString operator +(DnsString a, DnsString b) { if (a == null) { throw new ArgumentNullException("a"); } if (b == null) { throw new ArgumentNullException("b"); } string text = a.Value + ((b.Value.Length > 1) ? b.Value : string.Empty); return new DnsString(text, text); } public static DnsString operator +(DnsString a, string b) { if (a == null) { throw new ArgumentNullException("a"); } if (string.IsNullOrWhiteSpace(b)) { throw new ArgumentException("'b' cannot be null or empty.", "b"); } b = ((b[0] == '.') ? b.Substring(1) : b); DnsString dnsString = Parse(b); return a + dnsString; } public override string ToString() { return Value; } public override int GetHashCode() { return Value.GetHashCode(StringComparison.Ordinal); } public override bool Equals(object obj) { return obj?.ToString().Equals(Value, StringComparison.Ordinal) ?? false; } public static DnsString Parse(string query) { if (query == null) { throw new ArgumentNullException("query"); } int num = 0; int num2 = 0; int num3 = 0; if (query.Length > 1 && query[0] == '.') { throw new ArgumentException("'" + query + "' is not a legal name, found leading root label.", "query"); } if (query.Length == 0 || (query.Length == 1 && query.Equals(".", StringComparison.Ordinal))) { return RootLabel; } foreach (char c in query) { if (c == '.') { if (num2 > 63) { throw new ArgumentException($"Label '{num3 + 1}' is longer than {63} bytes.", "query"); } num3++; num2 = 0; continue; } num2++; num++; switch (c) { case '-': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': continue; } if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { continue; } try { string text = s_idn.GetAscii(query); if (text[text.Length - 1] != '.') { text += "."; } string[] array = text.Split(new char[1] { '.' }, StringSplitOptions.RemoveEmptyEntries); return new DnsString(query, text, array.Length); } catch (Exception innerException) { throw new ArgumentException("'" + query + "' is not a valid hostname.", "query", innerException); } } if (num2 > 0) { num3++; if (num2 > 63) { throw new ArgumentException($"Label '{num3}' is longer than {63} bytes.", "query"); } } if (num + num3 + 1 > 255) { throw new ArgumentException($"Octet length of '{query}' exceeds maximum of {255} bytes.", "query"); } if (query[query.Length - 1] != '.') { return new DnsString(query, query + ".", num3); } return new DnsString(query, query, num3); } public static DnsString FromResponseQueryString(string query) { string text = query; if (query.Length == 0 || query[query.Length - 1] != '.') { text += "."; } if (text.Contains("xn--", StringComparison.Ordinal)) { string unicode = s_idn.GetUnicode(text); return new DnsString(query, unicode); } return new DnsString(query, text); } } internal class DnsTcpMessageHandler : DnsMessageHandler { private class ClientPool : IDisposable { public class ClientEntry { public TcpClient Client { get; } public IPEndPoint Endpoint { get; } public int StartMillis { get; set; } = Environment.TickCount & 0x7FFFFFFF; public int MaxLiveTime { get; set; } = 5000; public ClientEntry(TcpClient client, IPEndPoint endpoint) { Client = client; Endpoint = endpoint; } public void DisposeClient() { try { Client.Dispose(); } catch { } } } private bool _disposedValue; private readonly bool _enablePool; private ConcurrentQueue<ClientEntry> _clients = new ConcurrentQueue<ClientEntry>(); private readonly IPEndPoint _endpoint; public ClientPool(bool enablePool, IPEndPoint endpoint) { _enablePool = enablePool; _endpoint = endpoint; } public async Task<ClientEntry> GetNextClient() { if (_disposedValue) { throw new ObjectDisposedException("ClientPool"); } ClientEntry entry = null; if (_enablePool) { while (entry == null && !TryDequeue(out entry)) { entry = new ClientEntry(new TcpClient(_endpoint.AddressFamily) { LingerState = new LingerOption(enable: true, 0) }, _endpoint); await entry.Client.ConnectAsync(_endpoint.Address, _endpoint.Port).ConfigureAwait(continueOnCapturedContext: false); } } else { entry = new ClientEntry(new TcpClient(_endpoint.AddressFamily), _endpoint); await entry.Client.ConnectAsync(_endpoint.Address, _endpoint.Port).ConfigureAwait(continueOnCapturedContext: false); } return entry; } public void Enqueue(ClientEntry entry) { if (_disposedValue) { throw new ObjectDisposedException("ClientPool"); } if (entry == null) { throw new ArgumentNullException("entry"); } if (!entry.Client.Client.RemoteEndPoint.Equals(_endpoint)) { throw new ArgumentException("Invalid endpoint."); } if (_enablePool && entry.Client.Connected && entry.StartMillis + entry.MaxLiveTime >= (Environment.TickCount & 0x7FFFFFFF)) { _clients.Enqueue(entry); } else { entry.DisposeClient(); } } public bool TryDequeue(out ClientEntry entry) { if (_disposedValue) { throw new ObjectDisposedException("ClientPool"); } bool result; while ((result = _clients.TryDequeue(out entry)) && (!entry.Client.Connected || entry.StartMillis + entry.MaxLiveTime < (Environment.TickCount & 0x7FFFFFFF))) { entry.DisposeClient(); } return result; } protected virtual void Dispose(bool disposing) { if (_disposedValue) { return; } if (disposing) { foreach (ClientEntry client in _clients) { client.DisposeClient(); } _clients = new ConcurrentQueue<ClientEntry>(); } _disposedValue = true; } public void Dispose() { Dispose(disposing: true); } } private readonly ConcurrentDictionary<IPEndPoint, ClientPool> _pools = new ConcurrentDictionary<IPEndPoint, ClientPool>(); public override DnsMessageHandleType Type { get; } = DnsMessageHandleType.TCP; public override DnsResponseMessage Query(IPEndPoint endpoint, DnsRequestMessage request, TimeSpan timeout) { if (timeout.TotalMilliseconds != -1.0 && timeout.TotalMilliseconds < 2147483647.0) { using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeout)) { return QueryAsync(endpoint, request, cancellationTokenSource.Token).WithCancellation(cancellationTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter() .GetResult(); } } return QueryAsync(endpoint, request, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } public override async Task<DnsResponseMessage> QueryAsync(IPEndPoint server, DnsRequestMessage request, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ClientPool pool; while (!_pools.TryGetValue(server, out pool)) { _pools.TryAdd(server, new ClientPool(enablePool: true, server)); } ClientPool.ClientEntry entry = await pool.GetNextClient().ConfigureAwait(continueOnCapturedContext: false); using (cancellationToken.Register(delegate { if (entry != null) { entry.DisposeClient(); } })) { _ = 1; try { DnsResponseMessage dnsResponseMessage = await QueryAsyncInternal(entry.Client, request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); DnsMessageHandler.ValidateResponse(request, dnsResponseMessage); pool.Enqueue(entry); return dnsResponseMessage; } catch { entry.DisposeClient(); throw; } } } private async Task<DnsResponseMessage> QueryAsyncInternal(TcpClient client, DnsRequestMessage request, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); NetworkStream stream = client.GetStream(); using (PooledBytes memory = new PooledBytes(1026)) { using DnsDatagramWriter writer = new DnsDatagramWriter(new ArraySegment<byte>(memory.Buffer, 2, memory.Buffer.Length - 2)); GetRequestData(request, writer); int index = writer.Index; memory.Buffer[0] = (byte)((uint)(index >> 8) & 0xFFu); memory.Buffer[1] = (byte)((uint)index & 0xFFu); await stream.WriteAsync(memory.Buffer, 0, index + 2, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); await stream.FlushAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } if (!stream.CanRead) { throw new TimeoutException(); } cancellationToken.ThrowIfCancellationRequested(); List<DnsResponseMessage> responses = new List<DnsResponseMessage>(); int num6 = default(int); do { int length; using (PooledBytes memory = new PooledBytes(2)) { int num = 0; while (true) { int num2 = num; int num3; if ((num = num2 + (num3 = await stream.ReadAsync(memory.Buffer, num, 2, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))) >= 2) { break; } if (num3 <= 0) { throw new TimeoutException(); } } length = (memory.Buffer[0] << 8) | memory.Buffer[1]; } if (length <= 0) { throw new TimeoutException(); } using PooledBytes memory = new PooledBytes(length); int num4 = 0; int num2 = ((length > 4096) ? 4096 : length); while (true) { bool flag = !cancellationToken.IsCancellationRequested; if (flag) { int num5 = num4; flag = (num4 = num5 + (num6 = await stream.ReadAsync(memory.Buffer, num4, num2, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))) < length; } if (!flag) { break; } if (num6 <= 0) { throw new TimeoutException(); } if (num4 + num2 > length) { num2 = length - num4; if (num2 <= 0) { break; } } } DnsResponseMessage responseMessage = GetResponseMessage(new ArraySegment<byte>(memory.Buffer, 0, num4)); responses.Add(responseMessage); } while (stream.DataAvailable && !cancellationToken.IsCancellationRequested); return DnsResponseMessage.Combine(responses); } } internal class DnsUdpMessageHandler : DnsMessageHandler { private const int MaxSize = 4096; public override DnsMessageHandleType Type { get; } = DnsMessageHandleType.UDP; public override DnsResponseMessage Query(IPEndPoint server, DnsRequestMessage request, TimeSpan timeout) { UdpClient udpClient = new UdpClient(server.AddressFamily); try { int num = ((timeout.TotalMilliseconds >= 2147483647.0) ? (-1) : ((int)timeout.TotalMilliseconds)); udpClient.Client.ReceiveTimeout = num; udpClient.Client.SendTimeout = num; using (DnsDatagramWriter dnsDatagramWriter = new DnsDatagramWriter()) { GetRequestData(request, dnsDatagramWriter); udpClient.Client.SendTo(dnsDatagramWriter.Data.Array, dnsDatagramWriter.Data.Offset, dnsDatagramWriter.Data.Count, SocketFlags.None, server); } int num2 = ((udpClient.Available > 4096) ? udpClient.Available : 4096); using PooledBytes pooledBytes = new PooledBytes(num2); int count = udpClient.Client.Receive(pooledBytes.Buffer, 0, num2, SocketFlags.None); DnsResponseMessage responseMessage = GetResponseMessage(new ArraySegment<byte>(pooledBytes.Buffer, 0, count)); DnsMessageHandler.ValidateResponse(request, responseMessage); return responseMessage; } finally { try { udpClient.Dispose(); } catch { } } } public override async Task<DnsResponseMessage> QueryAsync(IPEndPoint endpoint, DnsRequestMessage request, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); UdpClient udpClient = new UdpClient(endpoint.AddressFamily); try { using (cancellationToken.Register(delegate { udpClient.Dispose(); })) { using (DnsDatagramWriter writer = new DnsDatagramWriter()) { GetRequestData(request, writer); await udpClient.SendAsync(writer.Data.Array, writer.Data.Count, endpoint).ConfigureAwait(continueOnCapturedContext: false); } int length = ((udpClient.Available > 4096) ? udpClient.Available : 4096); using PooledBytes memory = new PooledBytes(length); int count = await SocketTaskExtensions.ReceiveAsync(udpClient.Client, new ArraySegment<byte>(memory.Buffer), SocketFlags.None).ConfigureAwait(continueOnCapturedContext: false); DnsResponseMessage responseMessage = GetResponseMessage(new ArraySegment<byte>(memory.Buffer, 0, count)); DnsMessageHandler.ValidateResponse(request, responseMessage); return responseMessage; } } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted) { throw new TimeoutException(); } catch (ObjectDisposedException) { throw new TimeoutException(); } finally { try { udpClient.Dispose(); } catch { } } } } [Serializable] public class DnsXidMismatchException : Exception { public int RequestXid { get; } public int ResponseXid { get; } public DnsXidMismatchException(int requestXid, int responseXid) { RequestXid = requestXid; ResponseXid = responseXid; } } public interface IDnsQuery { IDnsQueryResponse Query(string query, QueryType queryType, QueryClass queryClass = QueryClass.IN); IDnsQueryResponse Query(DnsQuestion question); IDnsQueryResponse Query(DnsQuestion question, DnsQueryAndServerOptions queryOptions); IDnsQueryResponse QueryCache(DnsQuestion question); IDnsQueryResponse QueryCache(string query, QueryType queryType, QueryClass queryClass = QueryClass.IN); Task<IDnsQueryResponse> QueryAsync(string query, QueryType queryType, QueryClass queryClass = QueryClass.IN, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryAsync(DnsQuestion question, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryAsync(DnsQuestion question, DnsQueryAndServerOptions queryOptions, CancellationToken cancellationToken = default(CancellationToken)); IDnsQueryResponse QueryReverse(IPAddress ipAddress); IDnsQueryResponse QueryReverse(IPAddress ipAddress, DnsQueryAndServerOptions queryOptions); Task<IDnsQueryResponse> QueryReverseAsync(IPAddress ipAddress, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryReverseAsync(IPAddress ipAddress, DnsQueryAndServerOptions queryOptions, CancellationToken cancellationToken = default(CancellationToken)); IDnsQueryResponse QueryServer(IReadOnlyCollection<NameServer> servers, string query, QueryType queryType, QueryClass queryClass = QueryClass.IN); IDnsQueryResponse QueryServer(IReadOnlyCollection<NameServer> servers, DnsQuestion question); IDnsQueryResponse QueryServer(IReadOnlyCollection<NameServer> servers, DnsQuestion question, DnsQueryOptions queryOptions); IDnsQueryResponse QueryServer(IReadOnlyCollection<IPEndPoint> servers, string query, QueryType queryType, QueryClass queryClass = QueryClass.IN); IDnsQueryResponse QueryServer(IReadOnlyCollection<IPAddress> servers, string query, QueryType queryType, QueryClass queryClass = QueryClass.IN); Task<IDnsQueryResponse> QueryServerAsync(IReadOnlyCollection<NameServer> servers, string query, QueryType queryType, QueryClass queryClass = QueryClass.IN, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerAsync(IReadOnlyCollection<NameServer> servers, DnsQuestion question, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerAsync(IReadOnlyCollection<NameServer> servers, DnsQuestion question, DnsQueryOptions queryOptions, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerAsync(IReadOnlyCollection<IPAddress> servers, string query, QueryType queryType, QueryClass queryClass = QueryClass.IN, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerAsync(IReadOnlyCollection<IPEndPoint> servers, string query, QueryType queryType, QueryClass queryClass = QueryClass.IN, CancellationToken cancellationToken = default(CancellationToken)); IDnsQueryResponse QueryServerReverse(IReadOnlyCollection<IPAddress> servers, IPAddress ipAddress); IDnsQueryResponse QueryServerReverse(IReadOnlyCollection<IPEndPoint> servers, IPAddress ipAddress); IDnsQueryResponse QueryServerReverse(IReadOnlyCollection<NameServer> servers, IPAddress ipAddress); IDnsQueryResponse QueryServerReverse(IReadOnlyCollection<NameServer> servers, IPAddress ipAddress, DnsQueryOptions queryOptions); Task<IDnsQueryResponse> QueryServerReverseAsync(IReadOnlyCollection<IPAddress> servers, IPAddress ipAddress, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerReverseAsync(IReadOnlyCollection<IPEndPoint> servers, IPAddress ipAddress, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerReverseAsync(IReadOnlyCollection<NameServer> servers, IPAddress ipAddress, CancellationToken cancellationToken = default(CancellationToken)); Task<IDnsQueryResponse> QueryServerReverseAsync(IReadOnlyCollection<NameServer> servers, IPAddress ipAddress, DnsQueryOptions queryOptions, CancellationToken cancellationToken = default(CancellationToken)); } public interface IDnsQueryResponse { IReadOnlyList<DnsQuestion> Questions { get; } IReadOnlyList<DnsResourceRecord> Additionals { get; } IEnumerable<DnsResourceRecord> AllRecords { get; } IReadOnlyList<DnsResourceRecord> Answers { get; } IReadOnlyList<DnsResourceRecord> Authorities { get; } string AuditTrail { get; } string ErrorMessage { get; } bool HasError { get; } DnsResponseHeader Header { get; } int MessageSize { get; } NameServer NameServer { get; } DnsQuerySettings Settings { get; } } public interface ILookupClient : IDnsQuery { IReadOnlyCollection<NameServer> NameServers { get; } LookupClientSettings Settings { get; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] TimeSpan? MinimumCacheTimeout { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool EnableAuditTrail { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool UseCache { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool Recursion { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] int Retries { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool ThrowDnsErrors { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool UseRandomNameServer { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool ContinueOnDnsError { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] TimeSpan Timeout { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool UseTcpFallback { get; set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] bool UseTcpOnly { get; set; } } internal class DisposableIntPtr : IDisposable { private IntPtr _ptr; public IntPtr Ptr => _ptr; public bool IsValid { get; private set; } = true; private DisposableIntPtr() { } public static DisposableIntPtr Alloc(int size) { DisposableIntPtr disposableIntPtr = new DisposableIntPtr(); try { disposableIntPtr._ptr = Marshal.AllocHGlobal(size); } catch (OutOfMemoryException) { disposableIntPtr.IsValid = false; } return disposableIntPtr; } public void Dispose() { Marshal.FreeHGlobal(_ptr); } } public class LookupClient : ILookupClient, IDnsQuery { private enum HandleError { None, Throw, RetryCurrentServer, RetryNextServer, ReturnResponse } private class SkipWorker { private readonly Action _worker; private readonly int _skipFor = 5000; private int _lastRun; public SkipWorker(Action worker, int skip = 5000) { _worker = worker ?? throw new ArgumentNullException("worker"); if (skip <= 1) { throw new ArgumentOutOfRangeException("skip"); } _skipFor = skip; _lastRun = Environment.TickCount & 0x7FFFFFFF; } public void MaybeDoWork() { if (_lastRun + _skipFor < (Environment.TickCount & 0x7FFFFFFF)) { int lastRun = _lastRun; if (Interlocked.CompareExchange(ref _lastRun, Environment.TickCount & 0x7FFFFFFF, lastRun) == lastRun) { _worker(); } } } } private const int LogEventStartQuery = 1; private const int LogEventQuery = 2; private const int LogEventQueryCachedResult = 3; private const int LogEventQueryTruncated = 5; private const int LogEventQuerySuccess = 10; private const int LogEventQueryReturnResponseError = 11; private const int LogEventQuerySuccessEmpty = 12; private const int LogEventQueryRetryErrorNextServer = 20; private const int LogEventQueryRetryErrorSameServer = 21; private const int LogEventQueryFail = 90; private const int LogEventQueryBadTruncation = 91; private const int LogEventResponseOpt = 31; private const int LogEventResponseMissingOpt = 80; private readonly LookupClientOptions _originalOptions; private readonly DnsMessageHandler _messageHandler; private readonly DnsMessageHandler _tcpFallbackHandler; private readonly ILogger _logger; private readonly SkipWorker _skipper; private IReadOnlyCollection<NameServer> _resolvedNameServers; public IReadOnlyCollection<NameServer> NameServers => Settings.NameServers; public LookupClientSettings Settings { get; private set; } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] public TimeSpan? MinimumCacheTimeout { get { return Settings.MinimumCacheTimeout; } set { if (Settings.MinimumCacheTimeout != value) { _originalOptions.MinimumCacheTimeout = value; Settings = new LookupClientSettings(_originalOptions, Settings.NameServers); } } } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] public bool UseTcpFallback { get { return Settings.UseTcpFallback; } set { if (Settings.UseTcpFallback != value) { _originalOptions.UseTcpFallback = value; Settings = new LookupClientSettings(_originalOptions, Settings.NameServers); } } } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] public bool UseTcpOnly { get { return Settings.UseTcpOnly; } set { if (Settings.UseTcpOnly != value) { _originalOptions.UseTcpOnly = value; Settings = new LookupClientSettings(_originalOptions, Settings.NameServers); } } } [Obsolete("This property will be removed from LookupClient in the next version. Use LookupClientOptions to initialize LookupClient instead.")] pu
BepInEx/plugins/libs/System.Buffers.4.5.1/netstandard2.0/System.Buffers.dll
Decompiled 7 months agousing System; using System.Diagnostics; using System.Diagnostics.Tracing; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Threading; using FxResources.System.Buffers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyTitle("System.Buffers")] [assembly: AssemblyDescription("System.Buffers")] [assembly: AssemblyDefaultAlias("System.Buffers")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyProduct("Microsoft® .NET Framework")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyFileVersion("4.6.28619.01")] [assembly: AssemblyInformationalVersion("4.6.28619.01 @BuiltBy: dlab14-DDVSOWINAGE069 @Branch: release/2.1 @SrcCode: https://github.com/dotnet/corefx/tree/7601f4f6225089ffb291dc7d58293c7bbf5c5d4f")] [assembly: CLSCompliant(true)] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.0.3.0")] [module: UnverifiableCode] namespace FxResources.System.Buffers { internal static class SR { } } namespace System { internal static class SR { private static ResourceManager s_resourceManager; private static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(ResourceType)); internal static Type ResourceType { get; } = typeof(SR); internal static string ArgumentException_BufferNotFromPool => GetResourceString("ArgumentException_BufferNotFromPool", null); [MethodImpl(MethodImplOptions.NoInlining)] private static bool UsingResourceKeys() { return false; } internal static string GetResourceString(string resourceKey, string defaultString) { string text = null; try { text = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } if (defaultString != null && resourceKey.Equals(text, StringComparison.Ordinal)) { return defaultString; } return text; } internal static string Format(string resourceFormat, params object[] args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + string.Join(", ", args); } return string.Format(resourceFormat, args); } return resourceFormat; } internal static string Format(string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(string resourceFormat, object p1, object p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object p1, object p2, object p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(resourceFormat, p1, p2, p3); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.All)] internal class __BlockReflectionAttribute : Attribute { } } namespace System.Buffers { public abstract class ArrayPool<T> { private static ArrayPool<T> s_sharedInstance; public static ArrayPool<T> Shared { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Volatile.Read(ref s_sharedInstance) ?? EnsureSharedCreated(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static ArrayPool<T> EnsureSharedCreated() { Interlocked.CompareExchange(ref s_sharedInstance, Create(), null); return s_sharedInstance; } public static ArrayPool<T> Create() { return new DefaultArrayPool<T>(); } public static ArrayPool<T> Create(int maxArrayLength, int maxArraysPerBucket) { return new DefaultArrayPool<T>(maxArrayLength, maxArraysPerBucket); } public abstract T[] Rent(int minimumLength); public abstract void Return(T[] array, bool clearArray = false); } [EventSource(Name = "System.Buffers.ArrayPoolEventSource")] internal sealed class ArrayPoolEventSource : EventSource { internal enum BufferAllocatedReason { Pooled, OverMaximumSize, PoolExhausted } internal static readonly System.Buffers.ArrayPoolEventSource Log = new System.Buffers.ArrayPoolEventSource(); [Event(1, Level = EventLevel.Verbose)] internal unsafe void BufferRented(int bufferId, int bufferSize, int poolId, int bucketId) { EventData* ptr = stackalloc EventData[4]; *ptr = new EventData { Size = 4, DataPointer = (IntPtr)(&bufferId) }; ptr[1] = new EventData { Size = 4, DataPointer = (IntPtr)(&bufferSize) }; ptr[2] = new EventData { Size = 4, DataPointer = (IntPtr)(&poolId) }; ptr[3] = new EventData { Size = 4, DataPointer = (IntPtr)(&bucketId) }; WriteEventCore(1, 4, ptr); } [Event(2, Level = EventLevel.Informational)] internal unsafe void BufferAllocated(int bufferId, int bufferSize, int poolId, int bucketId, BufferAllocatedReason reason) { EventData* ptr = stackalloc EventData[5]; *ptr = new EventData { Size = 4, DataPointer = (IntPtr)(&bufferId) }; ptr[1] = new EventData { Size = 4, DataPointer = (IntPtr)(&bufferSize) }; ptr[2] = new EventData { Size = 4, DataPointer = (IntPtr)(&poolId) }; ptr[3] = new EventData { Size = 4, DataPointer = (IntPtr)(&bucketId) }; ptr[4] = new EventData { Size = 4, DataPointer = (IntPtr)(&reason) }; WriteEventCore(2, 5, ptr); } [Event(3, Level = EventLevel.Verbose)] internal void BufferReturned(int bufferId, int bufferSize, int poolId) { WriteEvent(3, bufferId, bufferSize, poolId); } } internal sealed class DefaultArrayPool<T> : ArrayPool<T> { private sealed class Bucket { internal readonly int _bufferLength; private readonly T[][] _buffers; private readonly int _poolId; private SpinLock _lock; private int _index; internal int Id => GetHashCode(); internal Bucket(int bufferLength, int numberOfBuffers, int poolId) { _lock = new SpinLock(Debugger.IsAttached); _buffers = new T[numberOfBuffers][]; _bufferLength = bufferLength; _poolId = poolId; } internal T[] Rent() { T[][] buffers = _buffers; T[] array = null; bool lockTaken = false; bool flag = false; try { _lock.Enter(ref lockTaken); if (_index < buffers.Length) { array = buffers[_index]; buffers[_index++] = null; flag = array == null; } } finally { if (lockTaken) { _lock.Exit(useMemoryBarrier: false); } } if (flag) { array = new T[_bufferLength]; System.Buffers.ArrayPoolEventSource log = System.Buffers.ArrayPoolEventSource.Log; if (log.IsEnabled()) { log.BufferAllocated(array.GetHashCode(), _bufferLength, _poolId, Id, System.Buffers.ArrayPoolEventSource.BufferAllocatedReason.Pooled); } } return array; } internal void Return(T[] array) { if (array.Length != _bufferLength) { throw new ArgumentException(System.SR.ArgumentException_BufferNotFromPool, "array"); } bool lockTaken = false; try { _lock.Enter(ref lockTaken); if (_index != 0) { _buffers[--_index] = array; } } finally { if (lockTaken) { _lock.Exit(useMemoryBarrier: false); } } } } private const int DefaultMaxArrayLength = 1048576; private const int DefaultMaxNumberOfArraysPerBucket = 50; private static T[] s_emptyArray; private readonly Bucket[] _buckets; private int Id => GetHashCode(); internal DefaultArrayPool() : this(1048576, 50) { } internal DefaultArrayPool(int maxArrayLength, int maxArraysPerBucket) { if (maxArrayLength <= 0) { throw new ArgumentOutOfRangeException("maxArrayLength"); } if (maxArraysPerBucket <= 0) { throw new ArgumentOutOfRangeException("maxArraysPerBucket"); } if (maxArrayLength > 1073741824) { maxArrayLength = 1073741824; } else if (maxArrayLength < 16) { maxArrayLength = 16; } int id = Id; int num = System.Buffers.Utilities.SelectBucketIndex(maxArrayLength); Bucket[] array = new Bucket[num + 1]; for (int i = 0; i < array.Length; i++) { array[i] = new Bucket(System.Buffers.Utilities.GetMaxSizeForBucket(i), maxArraysPerBucket, id); } _buckets = array; } public override T[] Rent(int minimumLength) { if (minimumLength < 0) { throw new ArgumentOutOfRangeException("minimumLength"); } if (minimumLength == 0) { return s_emptyArray ?? (s_emptyArray = new T[0]); } System.Buffers.ArrayPoolEventSource log = System.Buffers.ArrayPoolEventSource.Log; T[] array = null; int num = System.Buffers.Utilities.SelectBucketIndex(minimumLength); if (num < _buckets.Length) { int num2 = num; do { array = _buckets[num2].Rent(); if (array != null) { if (log.IsEnabled()) { log.BufferRented(array.GetHashCode(), array.Length, Id, _buckets[num2].Id); } return array; } } while (++num2 < _buckets.Length && num2 != num + 2); array = new T[_buckets[num]._bufferLength]; } else { array = new T[minimumLength]; } if (log.IsEnabled()) { int hashCode = array.GetHashCode(); int bucketId = -1; log.BufferRented(hashCode, array.Length, Id, bucketId); log.BufferAllocated(hashCode, array.Length, Id, bucketId, (num >= _buckets.Length) ? System.Buffers.ArrayPoolEventSource.BufferAllocatedReason.OverMaximumSize : System.Buffers.ArrayPoolEventSource.BufferAllocatedReason.PoolExhausted); } return array; } public override void Return(T[] array, bool clearArray = false) { if (array == null) { throw new ArgumentNullException("array"); } if (array.Length == 0) { return; } int num = System.Buffers.Utilities.SelectBucketIndex(array.Length); if (num < _buckets.Length) { if (clearArray) { Array.Clear(array, 0, array.Length); } _buckets[num].Return(array); } System.Buffers.ArrayPoolEventSource log = System.Buffers.ArrayPoolEventSource.Log; if (log.IsEnabled()) { log.BufferReturned(array.GetHashCode(), array.Length, Id); } } } internal static class Utilities { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SelectBucketIndex(int bufferSize) { uint num = (uint)(bufferSize - 1) >> 4; int num2 = 0; if (num > 65535) { num >>= 16; num2 = 16; } if (num > 255) { num >>= 8; num2 += 8; } if (num > 15) { num >>= 4; num2 += 4; } if (num > 3) { num >>= 2; num2 += 2; } if (num > 1) { num >>= 1; num2++; } return num2 + (int)num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int GetMaxSizeForBucket(int binIndex) { return 16 << binIndex; } } }