Decompiled source of LethalSSH v0.1.1

baer1.LethalSSH.dll

Decompiled 2 months ago
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Renci.SshNet;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("baer1.LethalSSH")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+27f95d17cffb6ce84f8b76af23974495ea207269")]
[assembly: AssemblyProduct("LethalSsh")]
[assembly: AssemblyTitle("baer1.LethalSSH")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LethalSsh
{
	[BepInPlugin("baer1.LethalSSH", "LethalSsh", "0.1.1")]
	public class LethalSsh : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
		public class ParsePlayerSentencePatch
		{
			private static bool Prefix(ref Terminal __instance, ref TerminalNode __result)
			{
				//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01db: Expected O, but got Unknown
				//IL_0136: Unknown result type (might be due to invalid IL or missing references)
				//IL_0140: Expected O, but got Unknown
				string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded);
				Logger.LogDebug((object)(">> ParsePlayerSentence " + text));
				string[] array = text.Split(" ");
				if (Instance.Active && Instance.sshShell != null && ((Stream)(object)Instance.sshShell).CanWrite)
				{
					Instance.sshShell.Write(text + "\n");
					return false;
				}
				if (array[0] == "ssh")
				{
					__result = ScriptableObject.CreateInstance<TerminalNode>();
					__result.clearPreviousText = true;
					switch (array.Length)
					{
					case 4:
					{
						string[] array2 = array[1].Split("@");
						if (array2.Length != 2)
						{
							__result.displayText = "Invalid arguments";
							break;
						}
						int result = 22;
						int.TryParse(array[2], out result);
						Instance.sshClient = new SshClient(array2[1], result, array2[0], array[3]);
						((BaseClient)Instance.sshClient).Connect();
						Instance.sshShell = Instance.sshClient.CreateShellStream("linux", 20u, 20u, 800u, 600u, 1024);
						__result.displayText = "";
						break;
					}
					case 3:
					{
						string[] array2 = array[1].Split("@");
						if (array2.Length != 2)
						{
							__result.displayText = "Invalid arguments";
							break;
						}
						Instance.sshClient = new SshClient(array2[1], array2[0], array[2]);
						((BaseClient)Instance.sshClient).Connect();
						Instance.sshShell = Instance.sshClient.CreateShellStream("linux", 50u, 50u, 800u, 600u, 1024);
						__result.displayText = "";
						break;
					}
					default:
						__result.displayText = "Invalid arguments\n";
						break;
					}
					Instance._sgrCloseTags.Clear();
					Instance._sgrDim = false;
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Terminal), "TextChanged")]
		public class TextChangedPatch
		{
			private static bool Prefix(ref Terminal __instance, string newText)
			{
				Logger.LogDebug((object)(">> TextChanged " + newText.Split("\n").Last()));
				if (!Instance.Active)
				{
					return true;
				}
				if (__instance.modifyingText)
				{
					__instance.modifyingText = false;
					return false;
				}
				Terminal obj = __instance;
				obj.textAdded += newText.Length - __instance.currentText.Length;
				if (__instance.textAdded < 0)
				{
					__instance.screenText.text = __instance.currentText;
					__instance.textAdded = 0;
				}
				else
				{
					__instance.currentText = newText;
				}
				__instance.forceScrollbarCoroutine = ((MonoBehaviour)__instance).StartCoroutine(__instance.forceScrollbarDown());
				return false;
			}
		}

		[HarmonyPatch(typeof(Terminal), "QuitTerminal")]
		public class QuitTerminalPatch
		{
			private static void Prefix()
			{
				Logger.LogDebug((object)">> QuitTerminal");
				Instance.ResetSSH();
			}
		}

		[HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")]
		public class StartDisconnectPatch
		{
			private static void Prefix()
			{
				Logger.LogDebug((object)">> StartDisconnect");
				Instance.ResetSSH();
			}
		}

		[HarmonyPatch(typeof(Terminal), "Update")]
		public class TerminalUpdatePatch
		{
			private static void Prefix(ref Terminal __instance)
			{
				if (!Instance.Active || Instance.sshShell == null || !((Stream)(object)Instance.sshShell).CanRead)
				{
					return;
				}
				string text = Instance.sshShell.Read();
				if (text.Length == 0)
				{
					return;
				}
				string text2 = Regex.Split(GeneralExtensions.Join<string>((__instance.currentText + text).Split("\n").TakeLast(50), (Func<string, string>)null, "\n"), "\\x1B\\[[0-3]?[jJ]").Last();
				__instance.currentText = Regex.Replace(enableANSI.Value ? Regex.Replace(text2, "\\x1B\\[([0-9;]*)[mM]", delegate(Match m)
				{
					StringBuilder sb = new StringBuilder();
					string[] array = m.Groups[1].Value.Split(";");
					Func<string, string, bool> next = null;
					string text3 = null;
					string[] array2 = array;
					foreach (string text4 in array2)
					{
						Logger.LogDebug((object)(">> Parsing ANSI code " + text4));
						if (next != null)
						{
							Logger.LogDebug((object)("Found next function, previous: " + text3));
							if (!next(text3, text4))
							{
								text3 = text4;
								Logger.LogDebug((object)("previous overwritten " + text3));
							}
							else
							{
								Logger.LogDebug((object)("previous not overwritten: " + text3));
							}
						}
						else
						{
							switch (text4)
							{
							case "1":
								Instance._sgrCloseTags.Insert(0, "</b>");
								sb.Append("<b>");
								break;
							case "2":
								Instance._sgrCloseTags.Insert(0, "<alpha=#FF>");
								Instance._sgrDim = true;
								sb.Append("<alpha=#33>");
								break;
							case "3":
								Instance._sgrCloseTags.Insert(0, "</i>");
								sb.Append("<i>");
								break;
							case "4":
								Instance._sgrCloseTags.Insert(0, "</u>");
								sb.Append("<u>");
								break;
							case "9":
								Instance._sgrCloseTags.Insert(0, "</s>");
								sb.Append("<s>");
								break;
							case "30":
							case "31":
							case "32":
							case "33":
							case "34":
							case "35":
							case "36":
							case "37":
							case "90":
							case "91":
							case "92":
							case "93":
							case "94":
							case "95":
							case "96":
							case "97":
								Instance._sgrCloseTags.Insert(0, "</color>");
								sb.Append("<color=#" + GetColorByCode(text4) + (Instance._sgrDim ? "33" : "") + ">");
								break;
							case "40":
							case "41":
							case "42":
							case "43":
							case "44":
							case "45":
							case "46":
							case "47":
							case "100":
							case "101":
							case "102":
							case "103":
							case "104":
							case "105":
							case "106":
							case "107":
								Instance._sgrCloseTags.Insert(0, "</mark>");
								sb.Append("<mark=#" + GetColorByCode(text4) + "55>");
								break;
							case "38":
							case "48":
								next = delegate(string _, string mode)
								{
									if (!(mode == "2"))
									{
										if (mode == "5")
										{
											next = delegate(string previous, string color)
											{
												if (previous == "38")
												{
													Instance._sgrCloseTags.Insert(0, "</color>");
													sb.Append("<color=#" + Get256ColorByCode(color) + (Instance._sgrDim ? "33" : "") + ">");
												}
												else
												{
													Instance._sgrCloseTags.Insert(0, "</mark>");
													sb.Append("<mark=#" + Get256ColorByCode(color) + "55>");
												}
												next = null;
												return false;
											};
										}
									}
									else
									{
										StringBuilder rgb = new StringBuilder();
										next = delegate(string _, string r)
										{
											rgb.Append(((byte)int.Parse(r)).ToString("X2"));
											next = delegate(string _, string g)
											{
												rgb.Append(((byte)int.Parse(g)).ToString("X2"));
												next = delegate(string previous, string b)
												{
													rgb.Append(((byte)int.Parse(b)).ToString("X2"));
													if (previous == "38")
													{
														Instance._sgrCloseTags.Insert(0, "</color>");
														sb.Append("<color=#" + rgb.ToString() + (Instance._sgrDim ? "33" : "") + ">");
													}
													else
													{
														Instance._sgrCloseTags.Insert(0, "</mark>");
														sb.Append("<mark=#" + rgb.ToString() + "55>");
													}
													next = null;
													return false;
												};
												return true;
											};
											return true;
										};
									}
									return true;
								};
								break;
							default:
							{
								string result = Instance._sgrCloseTags.ToString();
								Instance._sgrCloseTags.Clear();
								Instance._sgrDim = false;
								return result;
							}
							}
							text3 = text4;
						}
					}
					Logger.LogDebug((object)("<< Parsed \u001b[" + m.Groups[1].Value + "m: " + sb.ToString()));
					return sb.ToString();
				}) : text2, "\\x1B\\[[?;=0-9]*[a-zA-Z~]", "");
				if (!__instance.currentText.StartsWith("\n\n\n"))
				{
					__instance.currentText = "\n\n\n" + __instance.currentText.TrimStart('\n');
				}
				__instance.screenText.text = __instance.currentText;
				__instance.forceScrollbarCoroutine = ((MonoBehaviour)__instance).StartCoroutine(__instance.forceScrollbarDown());
			}
		}

		internal SshClient? sshClient;

		internal ShellStream? sshShell;

		internal StringBuilder _sgrCloseTags = new StringBuilder();

		internal bool _sgrDim = false;

		public static LethalSsh Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static Harmony? Harmony { get; set; }

		public bool Active
		{
			get
			{
				SshClient val = sshClient;
				return val != null && ((BaseClient)val).IsConnected;
			}
		}

		internal static ConfigEntry<bool> enableANSI { get; private set; }

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			enableANSI = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "enableFormatting", true, "Enable or disable text colorization and formatting.");
			Patch();
			Logger.LogInfo((object)"baer1.LethalSSH v0.1.1 has loaded!");
		}

		public static string GetColorByCode(string code)
		{
			if (code.StartsWith("4"))
			{
				code = $"3{code.Last()}";
			}
			else if (code.StartsWith("10"))
			{
				code = $"9{code.Last()}";
			}
			if (1 == 0)
			{
			}
			string result = code switch
			{
				"30" => "000000", 
				"31" => "AA0000", 
				"32" => "00AA00", 
				"33" => "AA5500", 
				"34" => "0000AA", 
				"35" => "AA00AA", 
				"36" => "00AAAA", 
				"37" => "AAAAAA", 
				"90" => "555555", 
				"91" => "FF5555", 
				"92" => "55FF55", 
				"93" => "FFFF55", 
				"94" => "5555FF", 
				"95" => "FF55FF", 
				"96" => "55FFFF", 
				_ => "FFFFFF", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string Get256ColorByCode(string code)
		{
			byte b;
			try
			{
				b = (byte)int.Parse(code);
			}
			catch
			{
				return "FFFFFF";
			}
			if (b <= 7)
			{
				return GetColorByCode($"3{b}");
			}
			if (b <= 15)
			{
				return GetColorByCode($"9{b - 8}");
			}
			if (b >= 232)
			{
				return string.Concat(Enumerable.Repeat((Enumerable.Range(0, 24).ToArray()[b - 232] * 10 + 8).ToString("X2"), 3));
			}
			byte[] array = new byte[3]
			{
				(byte)Math.Floor(((float)(int)b - 16f) / 36f),
				(byte)Math.Floor(((float)(int)b - 16f) % 36f / 6f),
				(byte)Math.Floor(((float)(int)b - 16f) % 6f)
			};
			StringBuilder stringBuilder = new StringBuilder();
			byte[] array2 = array;
			foreach (byte b2 in array2)
			{
				stringBuilder.Append((b2 == 0) ? "00" : (b2 * 40 + 55).ToString("X2"));
			}
			return stringBuilder.ToString();
		}

		internal static void Patch()
		{
			//IL_000d: 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)
			//IL_0018: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony = new Harmony("baer1.LethalSSH");
			}
			Logger.LogDebug((object)"Patching...");
			Harmony.PatchAll();
			Logger.LogDebug((object)"Finished patching!");
		}

		internal static void Unpatch()
		{
			Logger.LogDebug((object)"Unpatching...");
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Logger.LogDebug((object)"Finished unpatching!");
		}

		internal void ResetSSH()
		{
			if (Instance.Active)
			{
				((Stream)(object)Instance.sshShell).Close();
				((BaseClient)Instance.sshClient).Disconnect();
				Instance.sshClient = null;
				Instance._sgrCloseTags.Clear();
				Instance._sgrDim = false;
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "baer1.LethalSSH";

		public const string PLUGIN_NAME = "LethalSsh";

		public const string PLUGIN_VERSION = "0.1.1";
	}
}

Renci.SshNet.dll

Decompiled 2 months ago
#define TRACE
using System;
using System.Buffers.Binary;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Formats.Asn1;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.CodeAnalysis;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Macs;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Rfc8032;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Zlib;
using Renci.SshNet.Abstractions;
using Renci.SshNet.Channels;
using Renci.SshNet.Common;
using Renci.SshNet.Compression;
using Renci.SshNet.Connection;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Authentication;
using Renci.SshNet.Messages.Connection;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.NetConf;
using Renci.SshNet.Security;
using Renci.SshNet.Security.Cryptography;
using Renci.SshNet.Security.Cryptography.Ciphers;
using Renci.SshNet.Security.Cryptography.Ciphers.Modes;
using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
using Renci.SshNet.Sftp;
using Renci.SshNet.Sftp.Requests;
using Renci.SshNet.Sftp.Responses;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("2024.2.0.1")]
[assembly: AssemblyInformationalVersion("2024.2.0.1+74d4364c32")]
[assembly: CLSCompliant(false)]
[assembly: Guid("ad816c5e-6f13-4589-9f3e-59523f8b77a4")]
[assembly: InternalsVisibleTo("Renci.SshNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")]
[assembly: InternalsVisibleTo("Renci.SshNet.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")]
[assembly: InternalsVisibleTo("Renci.SshNet.Benchmarks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Renci")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © Renci 2010-2024")]
[assembly: AssemblyDescription("SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism.")]
[assembly: AssemblyProduct("SSH.NET")]
[assembly: AssemblyTitle("SSH.NET")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/sshnet/SSH.NET.git")]
[assembly: AssemblyVersion("2024.2.0.1")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[GeneratedCode("Nerdbank.GitVersioning.Tasks", "3.7.77.5761")]
[ExcludeFromCodeCoverage]
internal static class ThisAssembly
{
	internal const string AssemblyConfiguration = "Release";

	internal const string AssemblyFileVersion = "2024.2.0.1";

	internal const string AssemblyInformationalVersion = "2024.2.0.1+74d4364c32";

	internal const string AssemblyName = "Renci.SshNet";

	internal const string AssemblyTitle = "SSH.NET";

	internal const string AssemblyVersion = "2024.2.0.1";

	internal static readonly DateTime GitCommitDate = new DateTime(638667472230000000L, DateTimeKind.Utc);

	internal const string GitCommitId = "74d4364c32c523f2a7d9a3ddbfc3a304ee9fb023";

	internal const bool IsPrerelease = false;

	internal const bool IsPublicRelease = true;

	internal const string NuGetPackageVersion = "2024.2.0";

	internal const string PublicKey = "0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2";

	internal const string PublicKeyToken = "1cee9f8bde3db106";

	internal const string RootNamespace = "Renci.SshNet";
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Threading.Tasks
{
	internal static class TaskToAsyncResult
	{
		private sealed class TaskAsyncResult : IAsyncResult
		{
			internal readonly Task _task;

			private readonly AsyncCallback? _callback;

			public object? AsyncState { get; }

			public bool CompletedSynchronously { get; }

			public bool IsCompleted => _task.IsCompleted;

			public WaitHandle AsyncWaitHandle => ((IAsyncResult)_task).AsyncWaitHandle;

			internal TaskAsyncResult(Task task, object? state, AsyncCallback? callback)
			{
				_task = task;
				AsyncState = state;
				if (task.IsCompleted)
				{
					CompletedSynchronously = true;
					callback?.Invoke(this);
				}
				else if (callback != null)
				{
					_callback = callback;
					_task.ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().OnCompleted(delegate
					{
						_callback(this);
					});
				}
			}
		}

		public static IAsyncResult Begin(Task task, AsyncCallback? callback, object? state)
		{
			if (task == null)
			{
				throw new ArgumentNullException("task");
			}
			return new TaskAsyncResult(task, state, callback);
		}

		public static void End(IAsyncResult asyncResult)
		{
			Unwrap(asyncResult).GetAwaiter().GetResult();
		}

		public static TResult End<TResult>(IAsyncResult asyncResult)
		{
			return Unwrap<TResult>(asyncResult).GetAwaiter().GetResult();
		}

		public static Task Unwrap(IAsyncResult asyncResult)
		{
			if (asyncResult == null)
			{
				throw new ArgumentNullException("asyncResult");
			}
			return (asyncResult as TaskAsyncResult)?._task ?? throw new ArgumentException(null, "asyncResult");
		}

		public static Task<TResult> Unwrap<TResult>(IAsyncResult asyncResult)
		{
			if (asyncResult == null)
			{
				throw new ArgumentNullException("asyncResult");
			}
			return ((asyncResult as TaskAsyncResult)?._task as Task<TResult>) ?? throw new ArgumentException(null, "asyncResult");
		}
	}
}
namespace Renci.SshNet
{
	public abstract class AuthenticationMethod : IAuthenticationMethod
	{
		public abstract string Name { get; }

		public string Username { get; private set; }

		public string[] AllowedAuthentications { get; protected set; }

		protected AuthenticationMethod(string username)
		{
			ThrowHelper.ThrowIfNullOrWhiteSpace(username, "username");
			Username = username;
		}

		public abstract AuthenticationResult Authenticate(Session session);

		AuthenticationResult IAuthenticationMethod.Authenticate(ISession session)
		{
			return Authenticate((Session)session);
		}
	}
	public enum AuthenticationResult
	{
		Success,
		PartialSuccess,
		Failure
	}
	public abstract class BaseClient : IBaseClient, IDisposable
	{
		private readonly bool _ownsConnectionInfo;

		private readonly IServiceFactory _serviceFactory;

		private readonly object _keepAliveLock = new object();

		private TimeSpan _keepAliveInterval;

		private Timer? _keepAliveTimer;

		private ConnectionInfo _connectionInfo;

		private bool _isDisposed;

		internal ISession? Session { get; private set; }

		internal IServiceFactory ServiceFactory => _serviceFactory;

		public ConnectionInfo ConnectionInfo
		{
			get
			{
				CheckDisposed();
				return _connectionInfo;
			}
			private set
			{
				_connectionInfo = value;
			}
		}

		public virtual bool IsConnected
		{
			get
			{
				CheckDisposed();
				return IsSessionConnected();
			}
		}

		public TimeSpan KeepAliveInterval
		{
			get
			{
				CheckDisposed();
				return _keepAliveInterval;
			}
			set
			{
				CheckDisposed();
				value.EnsureValidTimeout("KeepAliveInterval");
				if (!(value == _keepAliveInterval))
				{
					if (value == Timeout.InfiniteTimeSpan)
					{
						StopKeepAliveTimer();
					}
					else if (_keepAliveTimer != null)
					{
						_keepAliveTimer.Change(value, value);
					}
					else if (IsSessionConnected())
					{
						_keepAliveTimer = CreateKeepAliveTimer(value, value);
					}
					_keepAliveInterval = value;
				}
			}
		}

		public event EventHandler<ExceptionEventArgs>? ErrorOccurred;

		public event EventHandler<HostKeyEventArgs>? HostKeyReceived;

		public event EventHandler<SshIdentificationEventArgs>? ServerIdentificationReceived;

		protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo)
			: this(connectionInfo, ownsConnectionInfo, new ServiceFactory())
		{
		}

		private protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory)
		{
			ThrowHelper.ThrowIfNull(connectionInfo, "connectionInfo");
			ThrowHelper.ThrowIfNull(serviceFactory, "serviceFactory");
			_connectionInfo = connectionInfo;
			_ownsConnectionInfo = ownsConnectionInfo;
			_serviceFactory = serviceFactory;
			_keepAliveInterval = Timeout.InfiniteTimeSpan;
		}

		public void Connect()
		{
			CheckDisposed();
			if (IsConnected)
			{
				throw new InvalidOperationException("The client is already connected.");
			}
			OnConnecting();
			ISession session = Session;
			if (session == null || !session.IsConnected)
			{
				if (session != null)
				{
					DisposeSession(session);
				}
				Session = CreateAndConnectSession();
			}
			try
			{
				OnConnected();
			}
			catch
			{
				DisposeSession();
				throw;
			}
			StartKeepAliveTimer();
		}

		public async Task ConnectAsync(CancellationToken cancellationToken)
		{
			CheckDisposed();
			cancellationToken.ThrowIfCancellationRequested();
			if (IsConnected)
			{
				throw new InvalidOperationException("The client is already connected.");
			}
			OnConnecting();
			ISession session = Session;
			if (session == null || !session.IsConnected)
			{
				if (session != null)
				{
					DisposeSession(session);
				}
				using CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource(ConnectionInfo.Timeout);
				using CancellationTokenSource linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellationTokenSource.Token);
				try
				{
					Session = await CreateAndConnectSessionAsync(linkedCancellationTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false);
				}
				catch (OperationCanceledException innerException) when (timeoutCancellationTokenSource.IsCancellationRequested)
				{
					throw new SshOperationTimeoutException("Connection has timed out.", innerException);
				}
			}
			try
			{
				OnConnected();
			}
			catch
			{
				DisposeSession();
				throw;
			}
			StartKeepAliveTimer();
		}

		public void Disconnect()
		{
			CheckDisposed();
			OnDisconnecting();
			StopKeepAliveTimer();
			DisposeSession();
			OnDisconnected();
		}

		[Obsolete("Use KeepAliveInterval to send a keep-alive message at regular intervals.")]
		public void SendKeepAlive()
		{
			CheckDisposed();
			SendKeepAliveMessage();
		}

		protected virtual void OnConnecting()
		{
		}

		protected virtual void OnConnected()
		{
		}

		protected virtual void OnDisconnecting()
		{
			Session?.OnDisconnecting();
		}

		protected virtual void OnDisconnected()
		{
		}

		private void Session_ErrorOccured(object? sender, ExceptionEventArgs e)
		{
			this.ErrorOccurred?.Invoke(this, e);
		}

		private void Session_HostKeyReceived(object? sender, HostKeyEventArgs e)
		{
			this.HostKeyReceived?.Invoke(this, e);
		}

		private void Session_ServerIdentificationReceived(object? sender, SshIdentificationEventArgs e)
		{
			this.ServerIdentificationReceived?.Invoke(this, e);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!_isDisposed && disposing)
			{
				Disconnect();
				if (_ownsConnectionInfo && _connectionInfo is IDisposable disposable)
				{
					disposable.Dispose();
				}
				_isDisposed = true;
			}
		}

		protected void CheckDisposed()
		{
			ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
		}

		private void StopKeepAliveTimer()
		{
			if (_keepAliveTimer != null)
			{
				_keepAliveTimer.Dispose();
				_keepAliveTimer = null;
			}
		}

		private void SendKeepAliveMessage()
		{
			ISession session = Session;
			if (session == null || !Monitor.TryEnter(_keepAliveLock))
			{
				return;
			}
			try
			{
				session.TrySendMessage(new IgnoreMessage());
			}
			finally
			{
				Monitor.Exit(_keepAliveLock);
			}
		}

		private void StartKeepAliveTimer()
		{
			if (!(_keepAliveInterval == Timeout.InfiniteTimeSpan) && _keepAliveTimer == null)
			{
				_keepAliveTimer = CreateKeepAliveTimer(_keepAliveInterval, _keepAliveInterval);
			}
		}

		private Timer CreateKeepAliveTimer(TimeSpan dueTime, TimeSpan period)
		{
			return new Timer(delegate
			{
				SendKeepAliveMessage();
			}, Session, dueTime, period);
		}

		private ISession CreateAndConnectSession()
		{
			ISession session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory());
			session.ServerIdentificationReceived += Session_ServerIdentificationReceived;
			session.HostKeyReceived += Session_HostKeyReceived;
			session.ErrorOccured += Session_ErrorOccured;
			try
			{
				session.Connect();
				return session;
			}
			catch
			{
				DisposeSession(session);
				throw;
			}
		}

		private async Task<ISession> CreateAndConnectSessionAsync(CancellationToken cancellationToken)
		{
			ISession session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory());
			session.ServerIdentificationReceived += Session_ServerIdentificationReceived;
			session.HostKeyReceived += Session_HostKeyReceived;
			session.ErrorOccured += Session_ErrorOccured;
			try
			{
				await session.ConnectAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				return session;
			}
			catch
			{
				DisposeSession(session);
				throw;
			}
		}

		private void DisposeSession(ISession session)
		{
			session.ErrorOccured -= Session_ErrorOccured;
			session.HostKeyReceived -= Session_HostKeyReceived;
			session.ServerIdentificationReceived -= Session_ServerIdentificationReceived;
			session.Dispose();
		}

		private void DisposeSession()
		{
			ISession session = Session;
			if (session != null)
			{
				Session = null;
				DisposeSession(session);
			}
		}

		private bool IsSessionConnected()
		{
			return Session?.IsConnected ?? false;
		}
	}
	public class CipherInfo
	{
		public int KeySize { get; private set; }

		public bool IsAead { get; private set; }

		public Func<byte[], byte[], Cipher> Cipher { get; private set; }

		public CipherInfo(int keySize, Func<byte[], byte[], Cipher> cipher, bool isAead = false)
		{
			CipherInfo cipherInfo = this;
			KeySize = keySize;
			Cipher = (byte[] key, byte[] iv) => cipher(key.Take(cipherInfo.KeySize / 8), iv);
			IsAead = isAead;
		}
	}
	internal sealed class ClientAuthentication : IClientAuthentication
	{
		private sealed class AuthenticationState
		{
			private readonly IList<IAuthenticationMethod> _supportedAuthenticationMethods;

			private readonly Dictionary<IAuthenticationMethod, int> _authenticationMethodPartialSuccessRegister;

			private readonly List<IAuthenticationMethod> _failedAuthenticationMethods;

			public AuthenticationState(IList<IAuthenticationMethod> supportedAuthenticationMethods)
			{
				_supportedAuthenticationMethods = supportedAuthenticationMethods;
				_failedAuthenticationMethods = new List<IAuthenticationMethod>();
				_authenticationMethodPartialSuccessRegister = new Dictionary<IAuthenticationMethod, int>();
			}

			public void RecordFailure(IAuthenticationMethod authenticationMethod)
			{
				_failedAuthenticationMethods.Add(authenticationMethod);
			}

			public void RecordPartialSuccess(IAuthenticationMethod authenticationMethod)
			{
				if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var value))
				{
					_authenticationMethodPartialSuccessRegister[authenticationMethod] = value + 1;
				}
				else
				{
					_authenticationMethodPartialSuccessRegister.Add(authenticationMethod, 1);
				}
			}

			public int GetPartialSuccessCount(IAuthenticationMethod authenticationMethod)
			{
				if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var value))
				{
					return value;
				}
				return 0;
			}

			public List<IAuthenticationMethod> GetSupportedAuthenticationMethods(string[] allowedAuthenticationMethods)
			{
				List<IAuthenticationMethod> list = new List<IAuthenticationMethod>();
				foreach (IAuthenticationMethod supportedAuthenticationMethod in _supportedAuthenticationMethods)
				{
					string name = supportedAuthenticationMethod.Name;
					for (int i = 0; i < allowedAuthenticationMethods.Length; i++)
					{
						if (allowedAuthenticationMethods[i] == name)
						{
							list.Add(supportedAuthenticationMethod);
							break;
						}
					}
				}
				return list;
			}

			public IEnumerable<IAuthenticationMethod> GetActiveAuthenticationMethods(List<IAuthenticationMethod> matchingAuthenticationMethods)
			{
				List<IAuthenticationMethod> skippedAuthenticationMethods = new List<IAuthenticationMethod>();
				for (int i = 0; i < matchingAuthenticationMethods.Count; i++)
				{
					IAuthenticationMethod authenticationMethod = matchingAuthenticationMethods[i];
					if (!_failedAuthenticationMethods.Contains(authenticationMethod))
					{
						if (_authenticationMethodPartialSuccessRegister.ContainsKey(authenticationMethod))
						{
							skippedAuthenticationMethods.Add(authenticationMethod);
						}
						else
						{
							yield return authenticationMethod;
						}
					}
				}
				foreach (IAuthenticationMethod item in skippedAuthenticationMethods)
				{
					yield return item;
				}
			}
		}

		private readonly int _partialSuccessLimit;

		internal int PartialSuccessLimit => _partialSuccessLimit;

		public ClientAuthentication(int partialSuccessLimit)
		{
			if (partialSuccessLimit < 1)
			{
				throw new ArgumentOutOfRangeException("partialSuccessLimit", "Cannot be less than one.");
			}
			_partialSuccessLimit = partialSuccessLimit;
		}

		public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session)
		{
			ThrowHelper.ThrowIfNull(connectionInfo, "connectionInfo");
			ThrowHelper.ThrowIfNull(session, "session");
			session.RegisterMessage("SSH_MSG_USERAUTH_FAILURE");
			session.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS");
			session.RegisterMessage("SSH_MSG_USERAUTH_BANNER");
			session.UserAuthenticationBannerReceived += connectionInfo.UserAuthenticationBannerReceived;
			try
			{
				SshAuthenticationException authenticationException = null;
				IAuthenticationMethod authenticationMethod = connectionInfo.CreateNoneAuthenticationMethod();
				if (authenticationMethod.Authenticate(session) != 0 && !TryAuthenticate(session, new AuthenticationState(connectionInfo.AuthenticationMethods), authenticationMethod.AllowedAuthentications, ref authenticationException))
				{
					throw authenticationException;
				}
			}
			finally
			{
				session.UserAuthenticationBannerReceived -= connectionInfo.UserAuthenticationBannerReceived;
				session.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE");
				session.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS");
				session.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER");
			}
		}

		private bool TryAuthenticate(ISession session, AuthenticationState authenticationState, string[] allowedAuthenticationMethods, ref SshAuthenticationException authenticationException)
		{
			if (allowedAuthenticationMethods.Length == 0)
			{
				authenticationException = new SshAuthenticationException("No authentication methods defined on SSH server.");
				return false;
			}
			List<IAuthenticationMethod> supportedAuthenticationMethods = authenticationState.GetSupportedAuthenticationMethods(allowedAuthenticationMethods);
			if (supportedAuthenticationMethods.Count == 0)
			{
				authenticationException = new SshAuthenticationException(string.Format(CultureInfo.InvariantCulture, "No suitable authentication method found to complete authentication ({0}).", string.Join(',', allowedAuthenticationMethods)));
				return false;
			}
			foreach (IAuthenticationMethod activeAuthenticationMethod in authenticationState.GetActiveAuthenticationMethods(supportedAuthenticationMethods))
			{
				if (authenticationState.GetPartialSuccessCount(activeAuthenticationMethod) >= _partialSuccessLimit)
				{
					authenticationException = new SshAuthenticationException($"Reached authentication attempt limit for method ({activeAuthenticationMethod.Name}).");
					continue;
				}
				AuthenticationResult authenticationResult = activeAuthenticationMethod.Authenticate(session);
				switch (authenticationResult)
				{
				case AuthenticationResult.PartialSuccess:
					authenticationState.RecordPartialSuccess(activeAuthenticationMethod);
					if (TryAuthenticate(session, authenticationState, activeAuthenticationMethod.AllowedAuthentications, ref authenticationException))
					{
						authenticationResult = AuthenticationResult.Success;
					}
					break;
				case AuthenticationResult.Failure:
					authenticationState.RecordFailure(activeAuthenticationMethod);
					authenticationException = new SshAuthenticationException($"Permission denied ({activeAuthenticationMethod.Name}).");
					break;
				case AuthenticationResult.Success:
					authenticationException = null;
					break;
				}
				if (authenticationResult != 0)
				{
					continue;
				}
				return true;
			}
			return false;
		}
	}
	public class ConnectionInfo : IConnectionInfoInternal, IConnectionInfo
	{
		internal const int DefaultPort = 22;

		private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30.0);

		private static readonly TimeSpan DefaultChannelCloseTimeout = TimeSpan.FromSeconds(1.0);

		private TimeSpan _timeout;

		private TimeSpan _channelCloseTimeout;

		public IDictionary<string, Func<IKeyExchange>> KeyExchangeAlgorithms { get; private set; }

		public IDictionary<string, CipherInfo> Encryptions { get; private set; }

		public IDictionary<string, HashInfo> HmacAlgorithms { get; private set; }

		public IDictionary<string, Func<byte[], KeyHostAlgorithm>> HostKeyAlgorithms { get; private set; }

		public IList<AuthenticationMethod> AuthenticationMethods { get; private set; }

		public IDictionary<string, Func<Compressor>> CompressionAlgorithms { get; private set; }

		public IDictionary<string, RequestInfo> ChannelRequests { get; private set; }

		public bool IsAuthenticated { get; private set; }

		public string Host { get; private set; }

		public int Port { get; private set; }

		public string Username { get; private set; }

		public ProxyTypes ProxyType { get; private set; }

		public string ProxyHost { get; private set; }

		public int ProxyPort { get; private set; }

		public string ProxyUsername { get; private set; }

		public string ProxyPassword { get; private set; }

		public TimeSpan Timeout
		{
			get
			{
				return _timeout;
			}
			set
			{
				value.EnsureValidTimeout("Timeout");
				_timeout = value;
			}
		}

		public TimeSpan ChannelCloseTimeout
		{
			get
			{
				return _channelCloseTimeout;
			}
			set
			{
				value.EnsureValidTimeout("ChannelCloseTimeout");
				_channelCloseTimeout = value;
			}
		}

		public Encoding Encoding { get; set; }

		public int RetryAttempts { get; set; }

		public int MaxSessions { get; set; }

		public string CurrentKeyExchangeAlgorithm { get; internal set; }

		public string CurrentServerEncryption { get; internal set; }

		public string CurrentClientEncryption { get; internal set; }

		public string CurrentServerHmacAlgorithm { get; internal set; }

		public string CurrentClientHmacAlgorithm { get; internal set; }

		public string CurrentHostKeyAlgorithm { get; internal set; }

		public string CurrentServerCompressionAlgorithm { get; internal set; }

		public string ServerVersion { get; internal set; }

		public string ClientVersion { get; internal set; }

		public string CurrentClientCompressionAlgorithm { get; internal set; }

		IList<IAuthenticationMethod> IConnectionInfoInternal.AuthenticationMethods => AuthenticationMethods.Cast<IAuthenticationMethod>().ToList();

		public event EventHandler<AuthenticationBannerEventArgs> AuthenticationBanner;

		public ConnectionInfo(string host, string username, params AuthenticationMethod[] authenticationMethods)
			: this(host, 22, username, ProxyTypes.None, null, 0, null, null, authenticationMethods)
		{
		}

		public ConnectionInfo(string host, int port, string username, params AuthenticationMethod[] authenticationMethods)
			: this(host, port, username, ProxyTypes.None, null, 0, null, null, authenticationMethods)
		{
		}

		public ConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params AuthenticationMethod[] authenticationMethods)
		{
			ThrowHelper.ThrowIfNull(host, "host");
			port.ValidatePort("port");
			ThrowHelper.ThrowIfNullOrWhiteSpace(username, "username");
			if (proxyType != 0)
			{
				ThrowHelper.ThrowIfNull(proxyHost, "proxyHost");
				proxyPort.ValidatePort("proxyPort");
			}
			ThrowHelper.ThrowIfNull(authenticationMethods, "authenticationMethods");
			if (authenticationMethods.Length == 0)
			{
				throw new ArgumentException("At least one authentication method should be specified.", "authenticationMethods");
			}
			Timeout = DefaultTimeout;
			ChannelCloseTimeout = DefaultChannelCloseTimeout;
			RetryAttempts = 10;
			MaxSessions = 10;
			Encoding = Encoding.UTF8;
			KeyExchangeAlgorithms = new Dictionary<string, Func<IKeyExchange>>
			{
				{
					"curve25519-sha256",
					() => new KeyExchangeECCurve25519()
				},
				{
					"curve25519-sha256@libssh.org",
					() => new KeyExchangeECCurve25519()
				},
				{
					"ecdh-sha2-nistp256",
					() => new KeyExchangeECDH256()
				},
				{
					"ecdh-sha2-nistp384",
					() => new KeyExchangeECDH384()
				},
				{
					"ecdh-sha2-nistp521",
					() => new KeyExchangeECDH521()
				},
				{
					"diffie-hellman-group-exchange-sha256",
					() => new KeyExchangeDiffieHellmanGroupExchangeSha256()
				},
				{
					"diffie-hellman-group-exchange-sha1",
					() => new KeyExchangeDiffieHellmanGroupExchangeSha1()
				},
				{
					"diffie-hellman-group16-sha512",
					() => new KeyExchangeDiffieHellmanGroup16Sha512()
				},
				{
					"diffie-hellman-group14-sha256",
					() => new KeyExchangeDiffieHellmanGroup14Sha256()
				},
				{
					"diffie-hellman-group14-sha1",
					() => new KeyExchangeDiffieHellmanGroup14Sha1()
				},
				{
					"diffie-hellman-group1-sha1",
					() => new KeyExchangeDiffieHellmanGroup1Sha1()
				}
			};
			Encryptions = new Dictionary<string, CipherInfo>
			{
				{
					"aes128-ctr",
					new CipherInfo(128, (byte[] key, byte[] iv) => new AesCipher(key, iv, AesCipherMode.CTR))
				},
				{
					"aes192-ctr",
					new CipherInfo(192, (byte[] key, byte[] iv) => new AesCipher(key, iv, AesCipherMode.CTR))
				},
				{
					"aes256-ctr",
					new CipherInfo(256, (byte[] key, byte[] iv) => new AesCipher(key, iv, AesCipherMode.CTR))
				},
				{
					"aes128-gcm@openssh.com",
					new CipherInfo(128, (byte[] key, byte[] iv) => new AesGcmCipher(key, iv, 4), isAead: true)
				},
				{
					"aes256-gcm@openssh.com",
					new CipherInfo(256, (byte[] key, byte[] iv) => new AesGcmCipher(key, iv, 4), isAead: true)
				},
				{
					"chacha20-poly1305@openssh.com",
					new CipherInfo(512, (byte[] key, byte[] iv) => new ChaCha20Poly1305Cipher(key, 4), isAead: true)
				},
				{
					"aes128-cbc",
					new CipherInfo(128, (byte[] key, byte[] iv) => new AesCipher(key, iv, AesCipherMode.CBC))
				},
				{
					"aes192-cbc",
					new CipherInfo(192, (byte[] key, byte[] iv) => new AesCipher(key, iv, AesCipherMode.CBC))
				},
				{
					"aes256-cbc",
					new CipherInfo(256, (byte[] key, byte[] iv) => new AesCipher(key, iv, AesCipherMode.CBC))
				},
				{
					"3des-cbc",
					new CipherInfo(192, (byte[] key, byte[] iv) => new TripleDesCipher(key, new CbcCipherMode(iv), null))
				}
			};
			HmacAlgorithms = new Dictionary<string, HashInfo>
			{
				{
					"hmac-sha2-256",
					new HashInfo(256, (byte[] key) => new HMACSHA256(key))
				},
				{
					"hmac-sha2-512",
					new HashInfo(512, (byte[] key) => new HMACSHA512(key))
				},
				{
					"hmac-sha1",
					new HashInfo(160, (byte[] key) => new HMACSHA1(key))
				},
				{
					"hmac-sha2-256-etm@openssh.com",
					new HashInfo(256, (byte[] key) => new HMACSHA256(key), isEncryptThenMAC: true)
				},
				{
					"hmac-sha2-512-etm@openssh.com",
					new HashInfo(512, (byte[] key) => new HMACSHA512(key), isEncryptThenMAC: true)
				},
				{
					"hmac-sha1-etm@openssh.com",
					new HashInfo(160, (byte[] key) => new HMACSHA1(key), isEncryptThenMAC: true)
				}
			};
			Dictionary<string, Func<byte[], KeyHostAlgorithm>> hostAlgs = new Dictionary<string, Func<byte[], KeyHostAlgorithm>>();
			hostAlgs.Add("ssh-ed25519-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate8 = new Certificate(data);
				return new CertificateHostAlgorithm("ssh-ed25519-cert-v01@openssh.com", certificate8, hostAlgs);
			});
			hostAlgs.Add("ecdsa-sha2-nistp256-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate7 = new Certificate(data);
				return new CertificateHostAlgorithm("ecdsa-sha2-nistp256-cert-v01@openssh.com", certificate7, hostAlgs);
			});
			hostAlgs.Add("ecdsa-sha2-nistp384-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate6 = new Certificate(data);
				return new CertificateHostAlgorithm("ecdsa-sha2-nistp384-cert-v01@openssh.com", certificate6, hostAlgs);
			});
			hostAlgs.Add("ecdsa-sha2-nistp521-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate5 = new Certificate(data);
				return new CertificateHostAlgorithm("ecdsa-sha2-nistp521-cert-v01@openssh.com", certificate5, hostAlgs);
			});
			hostAlgs.Add("rsa-sha2-512-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate4 = new Certificate(data);
				return new CertificateHostAlgorithm("rsa-sha2-512-cert-v01@openssh.com", certificate4, new RsaDigitalSignature((RsaKey)certificate4.Key, HashAlgorithmName.SHA512), hostAlgs);
			});
			hostAlgs.Add("rsa-sha2-256-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate3 = new Certificate(data);
				return new CertificateHostAlgorithm("rsa-sha2-256-cert-v01@openssh.com", certificate3, new RsaDigitalSignature((RsaKey)certificate3.Key, HashAlgorithmName.SHA256), hostAlgs);
			});
			hostAlgs.Add("ssh-rsa-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate2 = new Certificate(data);
				return new CertificateHostAlgorithm("ssh-rsa-cert-v01@openssh.com", certificate2, hostAlgs);
			});
			hostAlgs.Add("ssh-dss-cert-v01@openssh.com", delegate(byte[] data)
			{
				Certificate certificate = new Certificate(data);
				return new CertificateHostAlgorithm("ssh-dss-cert-v01@openssh.com", certificate, hostAlgs);
			});
			hostAlgs.Add("ssh-ed25519", (byte[] data) => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(new SshKeyData(data))));
			hostAlgs.Add("ecdsa-sha2-nistp256", (byte[] data) => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(new SshKeyData(data))));
			hostAlgs.Add("ecdsa-sha2-nistp384", (byte[] data) => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(new SshKeyData(data))));
			hostAlgs.Add("ecdsa-sha2-nistp521", (byte[] data) => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(new SshKeyData(data))));
			hostAlgs.Add("rsa-sha2-512", delegate(byte[] data)
			{
				RsaKey rsaKey2 = new RsaKey(new SshKeyData(data));
				return new KeyHostAlgorithm("rsa-sha2-512", rsaKey2, new RsaDigitalSignature(rsaKey2, HashAlgorithmName.SHA512));
			});
			hostAlgs.Add("rsa-sha2-256", delegate(byte[] data)
			{
				RsaKey rsaKey = new RsaKey(new SshKeyData(data));
				return new KeyHostAlgorithm("rsa-sha2-256", rsaKey, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256));
			});
			hostAlgs.Add("ssh-rsa", (byte[] data) => new KeyHostAlgorithm("ssh-rsa", new RsaKey(new SshKeyData(data))));
			hostAlgs.Add("ssh-dss", (byte[] data) => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))));
			HostKeyAlgorithms = hostAlgs;
			CompressionAlgorithms = new Dictionary<string, Func<Compressor>>
			{
				{ "none", null },
				{
					"zlib@openssh.com",
					() => new ZlibOpenSsh()
				}
			};
			ChannelRequests = new Dictionary<string, RequestInfo>
			{
				{
					"env",
					new EnvironmentVariableRequestInfo()
				},
				{
					"exec",
					new ExecRequestInfo()
				},
				{
					"exit-signal",
					new ExitSignalRequestInfo()
				},
				{
					"exit-status",
					new ExitStatusRequestInfo()
				},
				{
					"pty-req",
					new PseudoTerminalRequestInfo()
				},
				{
					"shell",
					new ShellRequestInfo()
				},
				{
					"signal",
					new SignalRequestInfo()
				},
				{
					"subsystem",
					new SubsystemRequestInfo()
				},
				{
					"window-change",
					new WindowChangeRequestInfo()
				},
				{
					"x11-req",
					new X11ForwardingRequestInfo()
				},
				{
					"xon-xoff",
					new XonXoffRequestInfo()
				},
				{
					"eow@openssh.com",
					new EndOfWriteRequestInfo()
				},
				{
					"keepalive@openssh.com",
					new KeepAliveRequestInfo()
				}
			};
			Host = host;
			Port = port;
			Username = username;
			ProxyType = proxyType;
			ProxyHost = proxyHost;
			ProxyPort = proxyPort;
			ProxyUsername = proxyUsername;
			ProxyPassword = proxyPassword;
			AuthenticationMethods = authenticationMethods;
		}

		internal void Authenticate(ISession session, IServiceFactory serviceFactory)
		{
			ThrowHelper.ThrowIfNull(serviceFactory, "serviceFactory");
			IsAuthenticated = false;
			serviceFactory.CreateClientAuthentication().Authenticate(this, session);
			IsAuthenticated = true;
		}

		void IConnectionInfoInternal.UserAuthenticationBannerReceived(object sender, MessageEventArgs<BannerMessage> e)
		{
			this.AuthenticationBanner?.Invoke(this, new AuthenticationBannerEventArgs(Username, e.Message.Message, e.Message.Language));
		}

		IAuthenticationMethod IConnectionInfoInternal.CreateNoneAuthenticationMethod()
		{
			return new NoneAuthenticationMethod(Username);
		}
	}
	public class ExpectAction
	{
		public Regex Expect { get; private set; }

		public Action<string> Action { get; private set; }

		public ExpectAction(Regex expect, Action<string> action)
		{
			ThrowHelper.ThrowIfNull(expect, "expect");
			ThrowHelper.ThrowIfNull(action, "action");
			Expect = expect;
			Action = action;
		}

		public ExpectAction(string expect, Action<string> action)
		{
			ThrowHelper.ThrowIfNull(expect, "expect");
			ThrowHelper.ThrowIfNull(action, "action");
			Expect = new Regex(Regex.Escape(expect));
			Action = action;
		}
	}
	public abstract class ForwardedPort : IForwardedPort, IDisposable
	{
		internal ISession Session { get; set; }

		public abstract bool IsStarted { get; }

		public event EventHandler Closing;

		public event EventHandler<ExceptionEventArgs> Exception;

		public event EventHandler<PortForwardEventArgs> RequestReceived;

		public virtual void Start()
		{
			CheckDisposed();
			if (IsStarted)
			{
				throw new InvalidOperationException("Forwarded port is already started.");
			}
			if (Session == null)
			{
				throw new InvalidOperationException("Forwarded port is not added to a client.");
			}
			if (!Session.IsConnected)
			{
				throw new SshConnectionException("Client not connected.");
			}
			Session.ErrorOccured += Session_ErrorOccured;
			StartPort();
		}

		public virtual void Stop()
		{
			if (IsStarted)
			{
				StopPort(Session.ConnectionInfo.Timeout);
			}
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected abstract void StartPort();

		protected virtual void StopPort(TimeSpan timeout)
		{
			timeout.EnsureValidTimeout("timeout");
			RaiseClosing();
			ISession session = Session;
			if (session != null)
			{
				session.ErrorOccured -= Session_ErrorOccured;
			}
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				ISession session = Session;
				if (session != null)
				{
					StopPort(session.ConnectionInfo.Timeout);
					Session = null;
				}
			}
		}

		protected abstract void CheckDisposed();

		protected void RaiseExceptionEvent(Exception exception)
		{
			this.Exception?.Invoke(this, new ExceptionEventArgs(exception));
		}

		protected void RaiseRequestReceived(string host, uint port)
		{
			this.RequestReceived?.Invoke(this, new PortForwardEventArgs(host, port));
		}

		private void RaiseClosing()
		{
			this.Closing?.Invoke(this, EventArgs.Empty);
		}

		private void Session_ErrorOccured(object sender, ExceptionEventArgs e)
		{
			RaiseExceptionEvent(e.Exception);
		}
	}
	public class ForwardedPortDynamic : ForwardedPort
	{
		private ForwardedPortStatus _status;

		private bool _isDisposed;

		private Socket _listener;

		private CountdownEvent _pendingChannelCountdown;

		public string BoundHost { get; }

		public uint BoundPort { get; }

		public override bool IsStarted => _status == ForwardedPortStatus.Started;

		public ForwardedPortDynamic(uint port)
			: this(string.Empty, port)
		{
		}

		public ForwardedPortDynamic(string host, uint port)
		{
			BoundHost = host;
			BoundPort = port;
			_status = ForwardedPortStatus.Stopped;
		}

		protected override void StartPort()
		{
			if (!ForwardedPortStatus.ToStarting(ref _status))
			{
				return;
			}
			try
			{
				InternalStart();
			}
			catch (Exception)
			{
				_status = ForwardedPortStatus.Stopped;
				throw;
			}
		}

		protected override void StopPort(TimeSpan timeout)
		{
			timeout.EnsureValidTimeout("timeout");
			if (ForwardedPortStatus.ToStopping(ref _status))
			{
				base.StopPort(timeout);
				StopListener();
				InternalStop(timeout);
				_status = ForwardedPortStatus.Stopped;
			}
		}

		protected override void CheckDisposed()
		{
			ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
		}

		protected override void Dispose(bool disposing)
		{
			if (!_isDisposed)
			{
				base.Dispose(disposing);
				InternalDispose(disposing);
				_isDisposed = true;
			}
		}

		private void InternalStart()
		{
			InitializePendingChannelCountdown();
			IPAddress address = IPAddress.Any;
			if (!string.IsNullOrEmpty(BoundHost))
			{
				address = Dns.GetHostAddresses(BoundHost)[0];
			}
			IPEndPoint iPEndPoint = new IPEndPoint(address, (int)BoundPort);
			_listener = new Socket(iPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
			{
				NoDelay = true
			};
			_listener.Bind(iPEndPoint);
			_listener.Listen(5);
			base.Session.ErrorOccured += Session_ErrorOccured;
			base.Session.Disconnected += Session_Disconnected;
			_status = ForwardedPortStatus.Started;
			StartAccept(null);
		}

		private void StartAccept(SocketAsyncEventArgs e)
		{
			if (e == null)
			{
				e = new SocketAsyncEventArgs();
				e.Completed += AcceptCompleted;
			}
			else
			{
				e.AcceptSocket = null;
			}
			if (!IsStarted)
			{
				return;
			}
			try
			{
				if (!_listener.AcceptAsync(e))
				{
					AcceptCompleted(null, e);
				}
			}
			catch (ObjectDisposedException)
			{
				if (_status == ForwardedPortStatus.Stopping || _status == ForwardedPortStatus.Stopped)
				{
					return;
				}
				throw;
			}
		}

		private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
		{
			SocketError socketError = e.SocketError;
			if ((socketError != SocketError.OperationAborted && socketError != SocketError.NotSocket) || 1 == 0)
			{
				Socket acceptSocket = e.AcceptSocket;
				if (e.SocketError != 0)
				{
					StartAccept(e);
					CloseClientSocket(acceptSocket);
				}
				else
				{
					StartAccept(e);
					ProcessAccept(acceptSocket);
				}
			}
		}

		private void ProcessAccept(Socket clientSocket)
		{
			if (!IsStarted)
			{
				CloseClientSocket(clientSocket);
				return;
			}
			CountdownEvent pendingChannelCountdown = _pendingChannelCountdown;
			pendingChannelCountdown.AddCount();
			try
			{
				using IChannelDirectTcpip channelDirectTcpip = base.Session.CreateChannelDirectTcpip();
				channelDirectTcpip.Exception += Channel_Exception;
				if (!HandleSocks(channelDirectTcpip, clientSocket, base.Session.ConnectionInfo.Timeout))
				{
					CloseClientSocket(clientSocket);
				}
				else
				{
					channelDirectTcpip.Bind();
				}
			}
			catch (Exception exception)
			{
				RaiseExceptionEvent(exception);
				CloseClientSocket(clientSocket);
			}
			finally
			{
				try
				{
					pendingChannelCountdown.Signal();
				}
				catch (ObjectDisposedException)
				{
				}
			}
		}

		private void InitializePendingChannelCountdown()
		{
			Interlocked.Exchange(ref _pendingChannelCountdown, new CountdownEvent(1))?.Dispose();
		}

		private bool HandleSocks(IChannelDirectTcpip channel, Socket clientSocket, TimeSpan timeout)
		{
			base.Closing += closeClientSocket;
			try
			{
				int num = SocketAbstraction.ReadByte(clientSocket, timeout);
				return num switch
				{
					-1 => false, 
					4 => HandleSocks4(clientSocket, channel, timeout), 
					5 => HandleSocks5(clientSocket, channel, timeout), 
					_ => throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "SOCKS version {0} is not supported.", num)), 
				};
			}
			catch (SocketException ex)
			{
				if (ex.SocketErrorCode != SocketError.ConnectionAborted)
				{
					RaiseExceptionEvent(ex);
				}
				return false;
			}
			finally
			{
				base.Closing -= closeClientSocket;
			}
			void closeClientSocket(object sender, EventArgs args)
			{
				CloseClientSocket(clientSocket);
			}
		}

		private static void CloseClientSocket(Socket clientSocket)
		{
			if (clientSocket.Connected)
			{
				try
				{
					clientSocket.Shutdown(SocketShutdown.Send);
				}
				catch (Exception)
				{
				}
			}
			clientSocket.Dispose();
		}

		private void StopListener()
		{
			_listener?.Dispose();
			ISession session = base.Session;
			if (session != null)
			{
				session.ErrorOccured -= Session_ErrorOccured;
				session.Disconnected -= Session_Disconnected;
			}
		}

		private void InternalStop(TimeSpan timeout)
		{
			_pendingChannelCountdown.Signal();
			_pendingChannelCountdown.Wait(timeout);
		}

		private void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				Socket listener = _listener;
				if (listener != null)
				{
					_listener = null;
					listener.Dispose();
				}
				CountdownEvent pendingChannelCountdown = _pendingChannelCountdown;
				if (pendingChannelCountdown != null)
				{
					_pendingChannelCountdown = null;
					pendingChannelCountdown.Dispose();
				}
			}
		}

		private void Session_Disconnected(object sender, EventArgs e)
		{
			ISession session = base.Session;
			if (session != null)
			{
				StopPort(session.ConnectionInfo.Timeout);
			}
		}

		private void Session_ErrorOccured(object sender, ExceptionEventArgs e)
		{
			ISession session = base.Session;
			if (session != null)
			{
				StopPort(session.ConnectionInfo.Timeout);
			}
		}

		private void Channel_Exception(object sender, ExceptionEventArgs e)
		{
			RaiseExceptionEvent(e.Exception);
		}

		private bool HandleSocks4(Socket socket, IChannelDirectTcpip channel, TimeSpan timeout)
		{
			if (SocketAbstraction.ReadByte(socket, timeout) == -1)
			{
				return false;
			}
			byte[] array = new byte[2];
			if (SocketAbstraction.Read(socket, array, 0, array.Length, timeout) == 0)
			{
				return false;
			}
			ushort port = BinaryPrimitives.ReadUInt16BigEndian(array);
			byte[] array2 = new byte[4];
			if (SocketAbstraction.Read(socket, array2, 0, array2.Length, timeout) == 0)
			{
				return false;
			}
			IPAddress iPAddress = new IPAddress(array2);
			if (ReadString(socket, timeout) == null)
			{
				return false;
			}
			string text = iPAddress.ToString();
			RaiseRequestReceived(text, port);
			channel.Open(text, port, this, socket);
			SocketAbstraction.SendByte(socket, 0);
			if (channel.IsOpen)
			{
				SocketAbstraction.SendByte(socket, 90);
				SocketAbstraction.Send(socket, array, 0, array.Length);
				SocketAbstraction.Send(socket, array2, 0, array2.Length);
				return true;
			}
			SocketAbstraction.SendByte(socket, 91);
			return false;
		}

		private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan timeout)
		{
			int num = SocketAbstraction.ReadByte(socket, timeout);
			if (num == -1)
			{
				return false;
			}
			byte[] array = new byte[num];
			if (SocketAbstraction.Read(socket, array, 0, array.Length, timeout) == 0)
			{
				return false;
			}
			if (array.Min() == 0)
			{
				SocketAbstraction.Send(socket, new byte[2] { 5, 0 }, 0, 2);
			}
			else
			{
				SocketAbstraction.Send(socket, new byte[2] { 5, 255 }, 0, 2);
			}
			switch (SocketAbstraction.ReadByte(socket, timeout))
			{
			case -1:
				return false;
			default:
				throw new ProxyException("SOCKS5: Version 5 is expected.");
			case 5:
				if (SocketAbstraction.ReadByte(socket, timeout) == -1)
				{
					return false;
				}
				switch (SocketAbstraction.ReadByte(socket, timeout))
				{
				case -1:
					return false;
				default:
					throw new ProxyException("SOCKS5: 0 is expected for reserved byte.");
				case 0:
				{
					int num2 = SocketAbstraction.ReadByte(socket, timeout);
					if (num2 == -1)
					{
						return false;
					}
					string socks5Host = GetSocks5Host(num2, socket, timeout);
					if (socks5Host == null)
					{
						return false;
					}
					byte[] array2 = new byte[2];
					if (SocketAbstraction.Read(socket, array2, 0, array2.Length, timeout) == 0)
					{
						return false;
					}
					ushort port = BinaryPrimitives.ReadUInt16BigEndian(array2);
					RaiseRequestReceived(socks5Host, port);
					channel.Open(socks5Host, port, this, socket);
					byte[] array3 = CreateSocks5Reply(channel.IsOpen);
					SocketAbstraction.Send(socket, array3, 0, array3.Length);
					return true;
				}
				}
			}
		}

		private static string GetSocks5Host(int addressType, Socket socket, TimeSpan timeout)
		{
			switch (addressType)
			{
			case 1:
			{
				byte[] array3 = new byte[4];
				if (SocketAbstraction.Read(socket, array3, 0, 4, timeout) == 0)
				{
					return null;
				}
				return new IPAddress(array3).ToString();
			}
			case 3:
			{
				int num = SocketAbstraction.ReadByte(socket, timeout);
				if (num == -1)
				{
					return null;
				}
				byte[] array2 = new byte[num];
				if (SocketAbstraction.Read(socket, array2, 0, array2.Length, timeout) == 0)
				{
					return null;
				}
				return SshData.Ascii.GetString(array2, 0, array2.Length);
			}
			case 4:
			{
				byte[] array = new byte[16];
				if (SocketAbstraction.Read(socket, array, 0, 16, timeout) == 0)
				{
					return null;
				}
				return new IPAddress(array).ToString();
			}
			default:
				throw new ProxyException(string.Format(CultureInfo.InvariantCulture, "SOCKS5: Address type '{0}' is not supported.", addressType));
			}
		}

		private static byte[] CreateSocks5Reply(bool channelOpen)
		{
			byte[] array = new byte[10] { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
			if (channelOpen)
			{
				array[1] = 0;
			}
			else
			{
				array[1] = 1;
			}
			array[2] = 0;
			array[3] = 1;
			return array;
		}

		private static string ReadString(Socket socket, TimeSpan timeout)
		{
			StringBuilder stringBuilder = new StringBuilder();
			byte[] array = new byte[1];
			while (true)
			{
				if (SocketAbstraction.Read(socket, array, 0, 1, timeout) == 0)
				{
					return null;
				}
				byte b = array[0];
				if (b == 0)
				{
					break;
				}
				stringBuilder.Append((char)b);
			}
			return stringBuilder.ToString();
		}

		~ForwardedPortDynamic()
		{
			Dispose(disposing: false);
		}
	}
	public class ForwardedPortLocal : ForwardedPort
	{
		private ForwardedPortStatus _status;

		private bool _isDisposed;

		private Socket _listener;

		private CountdownEvent _pendingChannelCountdown;

		public string BoundHost { get; private set; }

		public uint BoundPort { get; private set; }

		public string Host { get; private set; }

		public uint Port { get; private set; }

		public override bool IsStarted => _status == ForwardedPortStatus.Started;

		public ForwardedPortLocal(uint boundPort, string host, uint port)
			: this(string.Empty, boundPort, host, port)
		{
		}

		public ForwardedPortLocal(string boundHost, string host, uint port)
			: this(boundHost, 0u, host, port)
		{
		}

		public ForwardedPortLocal(string boundHost, uint boundPort, string host, uint port)
		{
			ThrowHelper.ThrowIfNull(boundHost, "boundHost");
			ThrowHelper.ThrowIfNull(host, "host");
			boundPort.ValidatePort("boundPort");
			port.ValidatePort("port");
			BoundHost = boundHost;
			BoundPort = boundPort;
			Host = host;
			Port = port;
			_status = ForwardedPortStatus.Stopped;
		}

		protected override void StartPort()
		{
			if (!ForwardedPortStatus.ToStarting(ref _status))
			{
				return;
			}
			try
			{
				InternalStart();
			}
			catch (Exception)
			{
				_status = ForwardedPortStatus.Stopped;
				throw;
			}
		}

		protected override void StopPort(TimeSpan timeout)
		{
			timeout.EnsureValidTimeout("timeout");
			if (ForwardedPortStatus.ToStopping(ref _status))
			{
				base.StopPort(timeout);
				StopListener();
				InternalStop(timeout);
				_status = ForwardedPortStatus.Stopped;
			}
		}

		protected override void CheckDisposed()
		{
			ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
		}

		protected override void Dispose(bool disposing)
		{
			if (!_isDisposed)
			{
				base.Dispose(disposing);
				InternalDispose(disposing);
				_isDisposed = true;
			}
		}

		~ForwardedPortLocal()
		{
			Dispose(disposing: false);
		}

		private void InternalStart()
		{
			IPEndPoint iPEndPoint = new IPEndPoint(Dns.GetHostAddresses(BoundHost)[0], (int)BoundPort);
			_listener = new Socket(iPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
			{
				NoDelay = true
			};
			_listener.Bind(iPEndPoint);
			_listener.Listen(5);
			BoundPort = (uint)((IPEndPoint)_listener.LocalEndPoint).Port;
			base.Session.ErrorOccured += Session_ErrorOccured;
			base.Session.Disconnected += Session_Disconnected;
			InitializePendingChannelCountdown();
			_status = ForwardedPortStatus.Started;
			StartAccept(null);
		}

		private void StartAccept(SocketAsyncEventArgs e)
		{
			if (e == null)
			{
				e = new SocketAsyncEventArgs();
				e.Completed += AcceptCompleted;
			}
			else
			{
				e.AcceptSocket = null;
			}
			if (!IsStarted)
			{
				return;
			}
			try
			{
				if (!_listener.AcceptAsync(e))
				{
					AcceptCompleted(null, e);
				}
			}
			catch (ObjectDisposedException)
			{
				if (_status == ForwardedPortStatus.Stopping || _status == ForwardedPortStatus.Stopped)
				{
					return;
				}
				throw;
			}
		}

		private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
		{
			SocketError socketError = e.SocketError;
			if ((socketError != SocketError.OperationAborted && socketError != SocketError.NotSocket) || 1 == 0)
			{
				Socket acceptSocket = e.AcceptSocket;
				if (e.SocketError != 0)
				{
					StartAccept(e);
					CloseClientSocket(acceptSocket);
				}
				else
				{
					StartAccept(e);
					ProcessAccept(acceptSocket);
				}
			}
		}

		private void ProcessAccept(Socket clientSocket)
		{
			if (!IsStarted)
			{
				CloseClientSocket(clientSocket);
				return;
			}
			CountdownEvent pendingChannelCountdown = _pendingChannelCountdown;
			pendingChannelCountdown.AddCount();
			try
			{
				IPEndPoint iPEndPoint = (IPEndPoint)clientSocket.RemoteEndPoint;
				RaiseRequestReceived(iPEndPoint.Address.ToString(), (uint)iPEndPoint.Port);
				using IChannelDirectTcpip channelDirectTcpip = base.Session.CreateChannelDirectTcpip();
				channelDirectTcpip.Exception += Channel_Exception;
				channelDirectTcpip.Open(Host, Port, this, clientSocket);
				channelDirectTcpip.Bind();
			}
			catch (Exception exception)
			{
				RaiseExceptionEvent(exception);
				CloseClientSocket(clientSocket);
			}
			finally
			{
				try
				{
					pendingChannelCountdown.Signal();
				}
				catch (ObjectDisposedException)
				{
				}
			}
		}

		private void InitializePendingChannelCountdown()
		{
			Interlocked.Exchange(ref _pendingChannelCountdown, new CountdownEvent(1))?.Dispose();
		}

		private static void CloseClientSocket(Socket clientSocket)
		{
			if (clientSocket.Connected)
			{
				try
				{
					clientSocket.Shutdown(SocketShutdown.Send);
				}
				catch (Exception)
				{
				}
			}
			clientSocket.Dispose();
		}

		private void StopListener()
		{
			_listener?.Dispose();
			ISession session = base.Session;
			if (session != null)
			{
				session.ErrorOccured -= Session_ErrorOccured;
				session.Disconnected -= Session_Disconnected;
			}
		}

		private void InternalStop(TimeSpan timeout)
		{
			_pendingChannelCountdown.Signal();
			_pendingChannelCountdown.Wait(timeout);
		}

		private void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				Socket listener = _listener;
				if (listener != null)
				{
					_listener = null;
					listener.Dispose();
				}
				CountdownEvent pendingChannelCountdown = _pendingChannelCountdown;
				if (pendingChannelCountdown != null)
				{
					_pendingChannelCountdown = null;
					pendingChannelCountdown.Dispose();
				}
			}
		}

		private void Session_Disconnected(object sender, EventArgs e)
		{
			ISession session = base.Session;
			if (session != null)
			{
				StopPort(session.ConnectionInfo.Timeout);
			}
		}

		private void Session_ErrorOccured(object sender, ExceptionEventArgs e)
		{
			ISession session = base.Session;
			if (session != null)
			{
				StopPort(session.ConnectionInfo.Timeout);
			}
		}

		private void Channel_Exception(object sender, ExceptionEventArgs e)
		{
			RaiseExceptionEvent(e.Exception);
		}
	}
	public class ForwardedPortRemote : ForwardedPort
	{
		private ForwardedPortStatus _status;

		private bool _requestStatus;

		private EventWaitHandle _globalRequestResponse = new AutoResetEvent(initialState: false);

		private CountdownEvent _pendingChannelCountdown;

		private bool _isDisposed;

		public override bool IsStarted => _status == ForwardedPortStatus.Started;

		public IPAddress BoundHostAddress { get; private set; }

		public string BoundHost => BoundHostAddress.ToString();

		public uint BoundPort { get; private set; }

		public IPAddress HostAddress { get; private set; }

		public string Host => HostAddress.ToString();

		public uint Port { get; private set; }

		public ForwardedPortRemote(IPAddress boundHostAddress, uint boundPort, IPAddress hostAddress, uint port)
		{
			ThrowHelper.ThrowIfNull(boundHostAddress, "boundHostAddress");
			ThrowHelper.ThrowIfNull(hostAddress, "hostAddress");
			boundPort.ValidatePort("boundPort");
			port.ValidatePort("port");
			BoundHostAddress = boundHostAddress;
			BoundPort = boundPort;
			HostAddress = hostAddress;
			Port = port;
			_status = ForwardedPortStatus.Stopped;
		}

		public ForwardedPortRemote(uint boundPort, string host, uint port)
			: this(string.Empty, boundPort, host, port)
		{
		}

		public ForwardedPortRemote(string boundHost, uint boundPort, string host, uint port)
			: this(Dns.GetHostAddresses(boundHost)[0], boundPort, Dns.GetHostAddresses(host)[0], port)
		{
		}

		protected override void StartPort()
		{
			if (!ForwardedPortStatus.ToStarting(ref _status))
			{
				return;
			}
			InitializePendingChannelCountdown();
			try
			{
				base.Session.RegisterMessage("SSH_MSG_REQUEST_FAILURE");
				base.Session.RegisterMessage("SSH_MSG_REQUEST_SUCCESS");
				base.Session.RegisterMessage("SSH_MSG_CHANNEL_OPEN");
				base.Session.RequestSuccessReceived += Session_RequestSuccess;
				base.Session.RequestFailureReceived += Session_RequestFailure;
				base.Session.ChannelOpenReceived += Session_ChannelOpening;
				base.Session.SendMessage(new TcpIpForwardGlobalRequestMessage(BoundHost, BoundPort));
				base.Session.WaitOnHandle(_globalRequestResponse);
				if (!_requestStatus)
				{
					throw new SshException(string.Format(CultureInfo.CurrentCulture, "Port forwarding for '{0}' port '{1}' failed to start.", Host, Port));
				}
			}
			catch (Exception)
			{
				_status = ForwardedPortStatus.Stopped;
				base.Session.RequestSuccessReceived -= Session_RequestSuccess;
				base.Session.RequestFailureReceived -= Session_RequestFailure;
				base.Session.ChannelOpenReceived -= Session_ChannelOpening;
				throw;
			}
			_status = ForwardedPortStatus.Started;
		}

		protected override void StopPort(TimeSpan timeout)
		{
			timeout.EnsureValidTimeout("timeout");
			if (ForwardedPortStatus.ToStopping(ref _status))
			{
				base.StopPort(timeout);
				base.Session.SendMessage(new CancelTcpIpForwardGlobalRequestMessage(BoundHost, BoundPort));
				WaitHandle.WaitAny(new WaitHandle[2]
				{
					_globalRequestResponse,
					base.Session.MessageListenerCompleted
				}, timeout);
				base.Session.RequestSuccessReceived -= Session_RequestSuccess;
				base.Session.RequestFailureReceived -= Session_RequestFailure;
				base.Session.ChannelOpenReceived -= Session_ChannelOpening;
				_pendingChannelCountdown.Signal();
				_pendingChannelCountdown.Wait(timeout);
				_status = ForwardedPortStatus.Stopped;
			}
		}

		protected override void CheckDisposed()
		{
			ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
		}

		private void Session_ChannelOpening(object sender, MessageEventArgs<ChannelOpenMessage> e)
		{
			ChannelOpenMessage channelOpenMessage = e.Message;
			ChannelOpenInfo info2 = channelOpenMessage.Info;
			ForwardedTcpipChannelInfo info = info2 as ForwardedTcpipChannelInfo;
			if (info == null || !(info.ConnectedAddress == BoundHost) || info.ConnectedPort != BoundPort)
			{
				return;
			}
			if (!IsStarted)
			{
				base.Session.SendMessage(new ChannelOpenFailureMessage(channelOpenMessage.LocalChannelNumber, string.Empty, 1u));
				return;
			}
			ThreadAbstraction.ExecuteThread(delegate
			{
				CountdownEvent pendingChannelCountdown = _pendingChannelCountdown;
				pendingChannelCountdown.AddCount();
				try
				{
					RaiseRequestReceived(info.OriginatorAddress, info.OriginatorPort);
					using IChannelForwardedTcpip channelForwardedTcpip = base.Session.CreateChannelForwardedTcpip(channelOpenMessage.LocalChannelNumber, channelOpenMessage.InitialWindowSize, channelOpenMessage.MaximumPacketSize);
					channelForwardedTcpip.Exception += Channel_Exception;
					channelForwardedTcpip.Bind(new IPEndPoint(HostAddress, (int)Port), this);
				}
				catch (Exception exception)
				{
					RaiseExceptionEvent(exception);
				}
				finally
				{
					try
					{
						pendingChannelCountdown.Signal();
					}
					catch (ObjectDisposedException)
					{
					}
				}
			});
		}

		private void InitializePendingChannelCountdown()
		{
			Interlocked.Exchange(ref _pendingChannelCountdown, new CountdownEvent(1))?.Dispose();
		}

		private void Channel_Exception(object sender, ExceptionEventArgs exceptionEventArgs)
		{
			RaiseExceptionEvent(exceptionEventArgs.Exception);
		}

		private void Session_RequestFailure(object sender, EventArgs e)
		{
			_requestStatus = false;
			_globalRequestResponse.Set();
		}

		private void Session_RequestSuccess(object sender, MessageEventArgs<RequestSuccessMessage> e)
		{
			_requestStatus = true;
			if (BoundPort == 0)
			{
				BoundPort = (e.Message.BoundPort.HasValue ? e.Message.BoundPort.Value : 0u);
			}
			_globalRequestResponse.Set();
		}

		protected override void Dispose(bool disposing)
		{
			if (_isDisposed)
			{
				return;
			}
			base.Dispose(disposing);
			if (disposing)
			{
				ISession session = base.Session;
				if (session != null)
				{
					base.Session = null;
					session.RequestSuccessReceived -= Session_RequestSuccess;
					session.RequestFailureReceived -= Session_RequestFailure;
					session.ChannelOpenReceived -= Session_ChannelOpening;
				}
				EventWaitHandle globalRequestResponse = _globalRequestResponse;
				if (globalRequestResponse != null)
				{
					_globalRequestResponse = null;
					globalRequestResponse.Dispose();
				}
				CountdownEvent pendingChannelCountdown = _pendingChannelCountdown;
				if (pendingChannelCountdown != null)
				{
					_pendingChannelCountdown = null;
					pendingChannelCountdown.Dispose();
				}
			}
			_isDisposed = true;
		}
	}
	internal sealed class ForwardedPortStatus
	{
		public static readonly ForwardedPortStatus Stopped = new ForwardedPortStatus(1, "Stopped");

		public static readonly ForwardedPortStatus Stopping = new ForwardedPortStatus(2, "Stopping");

		public static readonly ForwardedPortStatus Started = new ForwardedPortStatus(3, "Started");

		public static readonly ForwardedPortStatus Starting = new ForwardedPortStatus(4, "Starting");

		private readonly int _value;

		private readonly string _name;

		private ForwardedPortStatus(int value, string name)
		{
			_value = value;
			_name = name;
		}

		public override bool Equals(object obj)
		{
			if (this == obj)
			{
				return true;
			}
			if (!(obj is ForwardedPortStatus forwardedPortStatus))
			{
				return false;
			}
			return forwardedPortStatus._value == _value;
		}

		public static bool operator ==(ForwardedPortStatus left, ForwardedPortStatus right)
		{
			return left?.Equals(right) ?? ((object)right == null);
		}

		public static bool operator !=(ForwardedPortStatus left, ForwardedPortStatus right)
		{
			return !(left == right);
		}

		public override int GetHashCode()
		{
			return _value;
		}

		public override string ToString()
		{
			return _name;
		}

		public static bool ToStopping(ref ForwardedPortStatus status)
		{
			ForwardedPortStatus forwardedPortStatus = Interlocked.CompareExchange(ref status, Stopping, Started);
			if (forwardedPortStatus == Stopping || forwardedPortStatus == Stopped)
			{
				return false;
			}
			if (status == Stopping)
			{
				return true;
			}
			forwardedPortStatus = Interlocked.CompareExchange(ref status, Stopping, Starting);
			if (forwardedPortStatus == Stopping || forwardedPortStatus == Stopped)
			{
				return false;
			}
			if (status == Stopping)
			{
				return true;
			}
			throw new InvalidOperationException($"Forwarded port cannot transition from '{forwardedPortStatus}' to '{Stopping}'.");
		}

		public static bool ToStarting(ref ForwardedPortStatus status)
		{
			ForwardedPortStatus forwardedPortStatus = Interlocked.CompareExchange(ref status, Starting, Stopped);
			if (forwardedPortStatus == Starting || forwardedPortStatus == Started)
			{
				return false;
			}
			if (status == Starting)
			{
				return true;
			}
			throw new InvalidOperationException($"Forwarded port cannot transition from '{forwardedPortStatus}' to '{Starting}'.");
		}
	}
	public class HashInfo
	{
		public int KeySize { get; private set; }

		public bool IsEncryptThenMAC { get; private set; }

		public Func<byte[], HashAlgorithm> HashAlgorithm { get; private set; }

		public HashInfo(int keySize, Func<byte[], HashAlgorithm> hash, bool isEncryptThenMAC = false)
		{
			HashInfo hashInfo = this;
			KeySize = keySize;
			HashAlgorithm = (byte[] key) => hash(key.Take(hashInfo.KeySize / 8));
			IsEncryptThenMAC = isEncryptThenMAC;
		}
	}
	internal interface IAuthenticationMethod
	{
		string[] AllowedAuthentications { get; }

		string Name { get; }

		AuthenticationResult Authenticate(ISession session);
	}
	public interface IBaseClient : IDisposable
	{
		ConnectionInfo ConnectionInfo { get; }

		bool IsConnected { get; }

		TimeSpan KeepAliveInterval { get; set; }

		event EventHandler<ExceptionEventArgs> ErrorOccurred;

		event EventHandler<HostKeyEventArgs> HostKeyReceived;

		event EventHandler<SshIdentificationEventArgs>? ServerIdentificationReceived;

		void Connect();

		Task ConnectAsync(CancellationToken cancellationToken);

		void Disconnect();

		void SendKeepAlive();
	}
	internal interface IClientAuthentication
	{
		void Authenticate(IConnectionInfoInternal connectionInfo, ISession session);
	}
	internal interface IConnectionInfo
	{
		TimeSpan ChannelCloseTimeout { get; }

		IDictionary<string, RequestInfo> ChannelRequests { get; }

		Encoding Encoding { get; }

		string Host { get; }

		int Port { get; }

		ProxyTypes ProxyType { get; }

		string ProxyHost { get; }

		int ProxyPort { get; }

		string ProxyUsername { get; }

		string ProxyPassword { get; }

		int RetryAttempts { get; }

		TimeSpan Timeout { get; }

		event EventHandler<AuthenticationBannerEventArgs> AuthenticationBanner;
	}
	internal interface IConnectionInfoInternal : IConnectionInfo
	{
		IList<IAuthenticationMethod> AuthenticationMethods { get; }

		void UserAuthenticationBannerReceived(object sender, MessageEventArgs<BannerMessage> e);

		IAuthenticationMethod CreateNoneAuthenticationMethod();
	}
	public interface IForwardedPort : IDisposable
	{
		event EventHandler Closing;
	}
	public interface IPrivateKeySource
	{
		IReadOnlyCollection<HostAlgorithm> HostKeyAlgorithms { get; }
	}
	public interface IRemotePathTransformation
	{
		string Transform(string path);
	}
	internal interface IServiceFactory
	{
		IClientAuthentication CreateClientAuthentication();

		INetConfSession CreateNetConfSession(ISession session, int operationTimeout);

		ISession CreateSession(ConnectionInfo connectionInfo, ISocketFactory socketFactory);

		ISftpSession CreateSftpSession(ISession session, int operationTimeout, Encoding encoding, ISftpResponseFactory sftpMessageFactory);

		PipeStream CreatePipeStream();

		IKeyExchange CreateKeyExchange(IDictionary<string, Func<IKeyExchange>> clientAlgorithms, string[] serverAlgorithms);

		ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize);

		ISftpResponseFactory CreateSftpResponseFactory();

		ShellStream CreateShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModeValues, int bufferSize);

		ShellStream CreateShellStreamNoTerminal(ISession session, int bufferSize);

		IRemotePathTransformation CreateRemotePathDoubleQuoteTransformation();

		IConnector CreateConnector(IConnectionInfo connectionInfo, ISocketFactory socketFactory);

		IProtocolVersionExchange CreateProtocolVersionExchange();

		ISocketFactory CreateSocketFactory();
	}
	internal interface ISession : IDisposable
	{
		IConnectionInfo ConnectionInfo { get; }

		bool IsConnected { get; }

		SemaphoreSlim SessionSemaphore { get; }

		WaitHandle MessageListenerCompleted { get; }

		event EventHandler<MessageEventArgs<ChannelCloseMessage>> ChannelCloseReceived;

		event EventHandler<MessageEventArgs<ChannelDataMessage>> ChannelDataReceived;

		event EventHandler<MessageEventArgs<ChannelEofMessage>> ChannelEofReceived;

		event EventHandler<MessageEventArgs<ChannelExtendedDataMessage>> ChannelExtendedDataReceived;

		event EventHandler<MessageEventArgs<ChannelFailureMessage>> ChannelFailureReceived;

		event EventHandler<MessageEventArgs<ChannelOpenConfirmationMessage>> ChannelOpenConfirmationReceived;

		event EventHandler<MessageEventArgs<ChannelOpenFailureMessage>> ChannelOpenFailureReceived;

		event EventHandler<MessageEventArgs<ChannelOpenMessage>> ChannelOpenReceived;

		event EventHandler<MessageEventArgs<ChannelRequestMessage>> ChannelRequestReceived;

		event EventHandler<MessageEventArgs<ChannelSuccessMessage>> ChannelSuccessReceived;

		event EventHandler<MessageEventArgs<ChannelWindowAdjustMessage>> ChannelWindowAdjustReceived;

		event EventHandler<EventArgs> Disconnected;

		event EventHandler<ExceptionEventArgs> ErrorOccured;

		event EventHandler<SshIdentificationEventArgs> ServerIdentificationReceived;

		event EventHandler<HostKeyEventArgs> HostKeyReceived;

		event EventHandler<MessageEventArgs<RequestSuccessMessage>> RequestSuccessReceived;

		event EventHandler<MessageEventArgs<RequestFailureMessage>> RequestFailureReceived;

		event EventHandler<MessageEventArgs<BannerMessage>> UserAuthenticationBannerReceived;

		void Connect();

		Task ConnectAsync(CancellationToken cancellationToken);

		IChannelSession CreateChannelSession();

		IChannelDirectTcpip CreateChannelDirectTcpip();

		IChannelForwardedTcpip CreateChannelForwardedTcpip(uint remoteChannelNumber, uint remoteWindowSize, uint remoteChannelDataPacketSize);

		void Disconnect();

		void OnDisconnecting();

		void RegisterMessage(string messageName);

		void SendMessage(Message message);

		bool TrySendMessage(Message message);

		void UnRegisterMessage(string messageName);

		void WaitOnHandle(WaitHandle waitHandle);

		void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout);

		WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception);

		WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout);
	}
	public interface ISftpClient : IBaseClient, IDisposable
	{
		uint BufferSize { get; set; }

		TimeSpan OperationTimeout { get; set; }

		int ProtocolVersion { get; }

		string WorkingDirectory { get; }

		void AppendAllLines(string path, IEnumerable<string> contents);

		void AppendAllLines(string path, IEnumerable<string> contents, Encoding encoding);

		void AppendAllText(string path, string contents);

		void AppendAllText(string path, string contents, Encoding encoding);

		StreamWriter AppendText(string path);

		StreamWriter AppendText(string path, Encoding encoding);

		IAsyncResult BeginDownloadFile(string path, Stream output);

		IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback? asyncCallback);

		IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback? asyncCallback, object? state, Action<ulong>? downloadCallback = null);

		IAsyncResult BeginListDirectory(string path, AsyncCallback? asyncCallback, object? state, Action<int>? listCallback = null);

		IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback? asyncCallback, object? state);

		IAsyncResult BeginUploadFile(Stream input, string path);

		IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback? asyncCallback);

		IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback? asyncCallback, object? state, Action<ulong>? uploadCallback = null);

		IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback? asyncCallback, object? state, Action<ulong>? uploadCallback = null);

		void ChangeDirectory(string path);

		Task ChangeDirectoryAsync(string path, CancellationToken cancellationToken = default(CancellationToken));

		void ChangePermissions(string path, short mode);

		SftpFileStream Create(string path);

		SftpFileStream Create(string path, int bufferSize);

		void CreateDirectory(string path);

		Task CreateDirectoryAsync(string path, CancellationToken cancellationToken = default(CancellationToken));

		StreamWriter CreateText(string path);

		StreamWriter CreateText(string path, Encoding encoding);

		void Delete(string path);

		Task DeleteAsync(string path, CancellationToken cancellationToken = default(CancellationToken));

		void DeleteDirectory(string path);

		Task DeleteDirectoryAsync(string path, CancellationToken cancellationToken = default(CancellationToken));

		void DeleteFile(string path);

		Task DeleteFileAsync(string path, CancellationToken cancellationToken);

		void DownloadFile(string path, Stream output, Action<ulong>? downloadCallback = null);

		void EndDownloadFile(IAsyncResult asyncResult);

		IEnumerable<ISftpFile> EndListDirectory(IAsyncResult asyncResult);

		IEnumerable<FileInfo> EndSynchronizeDirectories(IAsyncResult asyncResult);

		void EndUploadFile(IAsyncResult asyncResult);

		bool Exists(string path);

		ISftpFile Get(string path);

		SftpFileAttributes GetAttributes(string path);

		DateTime GetLastAccessTime(string path);

		DateTime GetLastAccessTimeUtc(string path);

		DateTime GetLastWriteTime(string path);

		DateTime GetLastWriteTimeUtc(string path);

		SftpFileSystemInformation GetStatus(string path);

		Task<SftpFileSystemInformation> GetStatusAsync(string path, CancellationToken cancellationToken);

		IEnumerable<ISftpFile> ListDirectory(string path, Action<int>? listCallback = null);

		IAsyncEnumerable<ISftpFile> ListDirectoryAsync(string path, CancellationToken cancellationToken);

		SftpFileStream Open(string path, FileMode mode);

		SftpFileStream Open(string path, FileMode mode, FileAccess access);

		Task<SftpFileStream> OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellationToken);

		SftpFileStream OpenRead(string path);

		StreamReader OpenText(string path);

		SftpFileStream OpenWrite(string path);

		byte[] ReadAllBytes(string path);

		string[] ReadAllLines(string path);

		string[] ReadAllLines(string path, Encoding encoding);

		string ReadAllText(string path);

		string ReadAllText(string path, Encoding encoding);

		IEnumerable<string> ReadLines(string path);

		IEnumerable<string> ReadLines(string path, Encoding encoding);

		void RenameFile(string oldPath, string newPath);

		void RenameFile(string oldPath, string newPath, bool isPosix);

		Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken);

		void SetLastAccessTime(string path, DateTime lastAccessTime);

		void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc);

		void SetLastWriteTime(string path, DateTime lastWriteTime);

		void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc);

		void SetAttributes(string path, SftpFileAttributes fileAttributes);

		void SymbolicLink(string path, string linkPath);

		IEnumerable<FileInfo> SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern);

		void UploadFile(Stream input, string path, Action<ulong>? uploadCallback = null);

		void UploadFile(Stream input, string path, bool canOverride, Action<ulong>? uploadCallback = null);

		void WriteAllBytes(string path, byte[] bytes);

		void WriteAllLines(string path, IEnumerable<string> contents);

		void WriteAllLines(string path, IEnumerable<string> contents, Encoding encoding);

		void WriteAllLines(string path, string[] contents);

		void WriteAllLines(string path, string[] contents, Encoding encoding);

		void WriteAllText(string path, string contents);

		void WriteAllText(string path, string contents, Encoding encoding);
	}
	public interface ISshClient : IBaseClient, IDisposable
	{
		IEnumerable<ForwardedPort> ForwardedPorts { get; }

		void AddForwardedPort(ForwardedPort port);

		void RemoveForwardedPort(ForwardedPort port);

		SshCommand CreateCommand(string commandText);

		SshCommand CreateCommand(string commandText, Encoding encoding);

		SshCommand RunCommand(string commandText);

		Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint>? terminalModes, int bufferSize);

		Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes);

		Shell CreateShell(Stream input, Stream output, Stream extendedOutput);

		Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint>? terminalModes, int bufferSize);

		Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary<TerminalModes, uint> terminalModes);

		Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput);

		Shell CreateShellNoTerminal(Stream input, Stream output, Stream extendedOutput, int bufferSize = -1);

		ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize);

		ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary<TerminalModes, uint>? terminalModeValues);

		ShellStream CreateShellStreamNoTerminal(int bufferSize = -1);
	}
	internal interface ISubsystemSession : IDisposable
	{
		int OperationTimeout { get; set; }

		bool IsOpen { get; }

		void Connect();

		void Disconnect();

		void WaitOnHandle(WaitHandle waitHandle, int millisecondsTimeout);

		bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout);

		int WaitAny(WaitHandle waitHandleA, WaitHandle waitHandleB, int millisecondsTimeout);

		int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout);

		WaitHandle[] CreateWaitHandleArray(params WaitHandle[] waitHandles);

		WaitHandle[] CreateWaitHandleArray(WaitHandle waitHandle1, WaitHandle waitHandle2);
	}
	public class KeyboardInteractiveAuthenticationMethod : AuthenticationMethod, IDisposable
	{
		private readonly RequestMessageKeyboardInteractive _requestMessage;

		private AuthenticationResult _authenticationResult = AuthenticationResult.Failure;

		private Session _session;

		private EventWaitHandle _authenticationCompleted = new AutoResetEvent(initialState: false);

		private Exception _exception;

		private bool _isDisposed;

		public override string Name => _requestMessage.MethodName;

		public event EventHandler<AuthenticationPromptEventArgs> AuthenticationPrompt;

		public KeyboardInteractiveAuthenticationMethod(string username)
			: base(username)
		{
			_requestMessage = new RequestMessageKeyboardInteractive(ServiceName.Connection, username);
		}

		public override AuthenticationResult Authenticate(Session session)
		{
			_session = session;
			session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived;
			session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived;
			session.UserAuthenticationInformationRequestReceived += Session_UserAuthenticationInformationRequestReceived;
			session.RegisterMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
			try
			{
				session.SendMessage(_requestMessage);
				session.WaitOnHandle(_authenticationCompleted);
			}
			finally
			{
				session.UnRegisterMessage("SSH_MSG_USERAUTH_INFO_REQUEST");
				session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
				session.UserAuthenticationFailureReceived -= Session_UserAuthenticationFailureReceived;
				session.UserAuthenticationInformationRequestReceived -= Session_UserAuthenticationInformationRequestReceived;
			}
			if (_exception != null)
			{
				ExceptionDispatchInfo.Capture(_exception).Throw();
			}
			return _authenticationResult;
		}

		private void Session_UserAuthenticationSuccessReceived(object sender, MessageEventArgs<SuccessMessage> e)
		{
			_authenticationResult = AuthenticationResult.Success;
			_authenticationCompleted.Set();
		}

		private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs<FailureMessage> e)
		{
			if (e.Message.PartialSuccess)
			{
				_authenticationResult = AuthenticationResult.PartialSuccess;
			}
			else
			{
				_authenticationResult = AuthenticationResult.Failure;
			}
			base.AllowedAuthentications = e.Message.AllowedAuthentications;
			_authenticationCompleted.Set();
		}

		private void Session_UserAuthenticationInformationRequestReceived(object sender, MessageEventArgs<InformationRequestMessage> e)
		{
			InformationRequestMessage message = e.Message;
			AuthenticationPromptEventArgs eventArgs = new AuthenticationPromptEventArgs(base.Username, message.Instruction, message.Language, message.Prompts);
			ThreadAbstraction.ExecuteThread(delegate
			{
				try
				{
					this.AuthenticationPrompt?.Invoke(this, eventArgs);
					InformationResponseMessage informationResponseMessage = new InformationResponseMessage();
					foreach (AuthenticationPrompt item in eventArgs.Prompts.OrderBy((AuthenticationPrompt r) => r.Id))
					{
						if (item.Response == null)
						{
							throw new SshAuthenticationException("AuthenticationPrompt.Response is null for prompt \"" + item.Request + "\". You can set this by subscribing to KeyboardInteractiveAuthenticationMethod.AuthenticationPrompt and inspecting the Prompts property of the event args.");
						}
						informationResponseMessage.Responses.Add(item.Response);
					}
					_session.SendMessage(informationResponseMessage);
				}
				catch (Exception exception)
				{
					_exception = exception;
					_authenticationCompleted.Set();
				}
			});
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!_isDisposed && disposing)
			{
				EventWaitHandle authenticationCompleted = _authenticationCompleted;
				if (authenticationCompleted != null)
				{
					_authenticationCompleted = null;
					authenticationCompleted.Dispose();
				}
				_isDisposed = true;
			}
		}
	}
	public class KeyboardInteractiveConnectionInfo : ConnectionInfo, IDisposable
	{
		private bool _isDisposed;

		public event EventHandler<AuthenticationPromptEventArgs> AuthenticationPrompt;

		public KeyboardInteractiveConnectionInfo(string host, string username)
			: this(host, 22, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, int port, string username)
			: this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort)
			: this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername)
			: this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort)
			: this(host, 22, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername)
			: this(host, 22, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword)
			: this(host, 22, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword)
		{
		}

		public KeyboardInteractiveConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword)
			: base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new KeyboardInteractiveAuthenticationMethod(username))
		{
			foreach (AuthenticationMethod authenticationMethod in base.AuthenticationMethods)
			{
				if (authenticationMethod is KeyboardInteractiveAuthenticationMethod keyboardInteractiveAuthenticationMethod)
				{
					keyboardInteractiveAuthenticationMethod.AuthenticationPrompt += AuthenticationMethod_AuthenticationPrompt;
				}
			}
		}

		private void AuthenticationMethod_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
		{
			this.AuthenticationPrompt?.Invoke(sender, e);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (_isDisposed || !disposing)
			{
				return;
			}
			if (base.AuthenticationMethods != null)
			{
				foreach (AuthenticationMethod authenticationMethod in base.AuthenticationMethods)
				{
					if (authenticationMethod is IDisposable disposable)
					{
						disposable.Dispose();
					}
				}
			}
			_isDisposed = true;
		}
	}
	public class MessageEventArgs<T> : EventArgs
	{
		public T Message { get; private set; }

		public MessageEventArgs(T message)
		{
			ThrowHelper.ThrowIfNull(message, "message");
			Message = message;
		}
	}
	public class NetConfClient : BaseClient
	{
		private int _operationTimeout;

		private INetConfSession? _netConfSession;

		public TimeSpan OperationTimeout
		{
			get
			{
				return TimeSpan.FromMilliseconds(_operationTimeout);
			}
			set
			{
				_operationTimeout = value.AsTimeout("OperationTimeout");
			}
		}

		internal INetConfSession? NetConfSession => _netConfSession;

		public XmlDocument ServerCapabilities
		{
			get
			{
				if (_netConfSession == null)
				{
					throw new SshConnectionException("Client not connected.");
				}
				return _netConfSession.ServerCapabilities;
			}
		}

		public XmlDocument ClientCapabilities
		{
			get
			{
				if (_netConfSession == null)
				{
					throw new SshConnectionException("Client not connected.");
				}
				return _netConfSession.ClientCapabilities;
			}
		}

		public bool AutomaticMessageIdHandling { get; set; }

		public NetConfClient(ConnectionInfo connectionInfo)
			: this(connectionInfo, ownsConnectionInfo: false)
		{
		}

		public NetConfClient(string host, int port, string username, string password)
			: this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true)
		{
		}

		public NetConfClient(string host, string username, string password)
			: this(host, 22, username, password)
		{
		}

		public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
			: this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
		{
		}

		public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles)
			: this(host, 22, username, keyFiles)
		{
		}

		private NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo)
			: this(connectionInfo, ownsConnectionInfo, new ServiceFactory())
		{
		}

		internal NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory)
			: base(connectionInfo, ownsConnectionInfo, serviceFactory)
		{
			_operationTimeout = -1;
			AutomaticMessageIdHandling = true;
		}

		public XmlDocument SendReceiveRpc(XmlDocument rpc)
		{
			if (_netConfSession == null)
			{
				throw new SshConnectionException("Client not connected.");
			}
			return _netConfSession.SendReceiveRpc(rpc, AutomaticMessageIdHandling);
		}

		public XmlDocument SendReceiveRpc(string xml)
		{
			XmlDocument xmlDocument = new XmlDocument();
			xmlDocument.LoadXml(xml);
			return SendReceiveRpc(xmlDocument);
		}

		public XmlDocument SendCloseRpc()
		{
			if (_netConfSession == null)
			{
				throw new SshConnectionException("Client not connected.");
			}
			XmlDocument xmlDocument = new XmlDocument();
			xmlDocument.LoadXml("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rpc message-id=\"6666\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><close-session/></rpc>");
			return _netConfSession.SendReceiveRpc(xmlDocument, AutomaticMessageIdHandling);
		}

		protected override void OnConnected()
		{
			base.OnConnected();
			_netConfSession = CreateAndConnectNetConfSession();
		}

		protected override void OnDisconnecting()
		{
			base.OnDisconnecting();
			_netConfSession?.Disconnect();
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			if (disposing && _netConfSession != null)
			{
				_netConfSession.Dispose();
				_netConfSession = null;
			}
		}

		private INetConfSession CreateAndConnectNetConfSession()
		{
			INetConfSession netConfSession = base.ServiceFactory.CreateNetConfSession(base.Session, _operationTimeout);
			try
			{
				netConfSession.Connect();
				return netConfSession;
			}
			catch
			{
				netConfSession.Dispose();
				throw;
			}
		}
	}
	public class NoneAuthenticationMethod : AuthenticationMethod, IDisposable
	{
		private AuthenticationResult _authenticationResult = AuthenticationResult.Failure;

		private EventWaitHandle _authenticationCompleted = new AutoResetEvent(initialState: false);

		private bool _isDisposed;

		public override string Name => "none";

		public NoneAuthenticationMethod(string username)
			: base(username)
		{
		}

		public override AuthenticationResult Authenticate(Session session)
		{
			ThrowHelper.ThrowIfNull(session, "session");
			session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived;
			session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived;
			try
			{
				session.SendMessage(new RequestMessageNone(ServiceName.Connection, base.Username));
				session.WaitOnHandle(_authenticationCompleted);
			}
			finally
			{
				session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
				session.UserAuthenticationFailureReceived -= Session_UserAuthenticationFailureReceived;
			}
			return _authenticationResult;
		}

		private void Session_UserAuthenticationSuccessReceived(object sender, MessageEventArgs<SuccessMessage> e)
		{
			_authenticationResult = AuthenticationResult.Success;
			_authenticationCompleted.Set();
		}

		private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs<FailureMessage> e)
		{
			if (e.Message.PartialSuccess)
			{
				_authenticationResult = AuthenticationResult.PartialSuccess;
			}
			else
			{
				_authenticationResult = AuthenticationResult.Failure;
			}
			base.AllowedAuthentications = e.Message.AllowedAuthentications;
			_authenticationCompleted.Set();
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!_isDisposed && disposing)
			{
				EventWaitHandle authenticationCompleted = _authenticationCompleted;
				if (authenticationCompleted != null)
				{
					authenticationCompleted.Dispose();
					_authenticationCompleted = null;
				}
				_isDisposed = true;
			}
		}
	}
	public class PasswordAuthenticationMethod : AuthenticationMethod, IDisposable
	{
		private readonly RequestMessagePassword _requestMessage;

		private readonly byte[] _password;

		private AuthenticationResult _authenticationResult = AuthenticationResult.Failure;

		private Session _session;

		private EventWaitHandle _authenticationCompleted = new AutoResetEvent(initialState: false);

		private Exception _exception;

		private bool _isDisposed;

		public override string Name => _requestMessage.MethodName;

		internal byte[] Password => _password;

		public event EventHandler<AuthenticationPasswordChangeEventArgs> PasswordExpired;

		public PasswordAuthenticationMethod(string username, string password)
			: this(username, Encoding.UTF8.GetBytes(password))
		{
		}

		public PasswordAuthenticationMethod(string username, byte[] password)
			: base(username)
		{
			ThrowHelper.ThrowIfNull(password, "password");
			_password = password;
			_requestMessage = new RequestMessagePassword(ServiceName.Connection, base.Username, _password);
		}

		public override AuthenticationResult Authenticate(Session session)
		{
			ThrowHelper.ThrowIfNull(session, "session");
			_session = session;
			session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived;
			session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived;
			session.UserAuthenticationPasswordChangeRequiredReceived += Session_UserAuthenticationPasswordChangeRequiredReceived;
			try
			{
				session.RegisterMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
				session.SendMessage(_requestMessage);
				session.WaitOnHandle(_authenticationCompleted);
			}
			finally
			{
				session.UnRegisterMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ");
				session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
				session.UserAuthenticationFailur