using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Messages.Transport; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Renci.SshNet.Tests { [TestClass] public class SshMessageFactoryTest { private SshMessageFactory _sshMessageFactory; private SshMessageFactoryOriginal _sshMessageFactoryOriginal; [TestInitialize] public void SetUp() { _sshMessageFactory = new SshMessageFactory(); _sshMessageFactoryOriginal = new SshMessageFactoryOriginal(); } [TestMethod] public void CreateShouldThrowSshExceptionWhenMessageIsNotEnabled() { const byte messageNumber = 60; try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_OutsideOfMessageNumberRange() { const byte messageNumber = 255; try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message); } } [TestMethod] public void CreateShouldThrowSshExceptionWhenMessageDoesNotExist_WithinMessageNumberRange() { const byte messageNumber = 5; try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not supported.", messageNumber), ex.Message); } } [TestMethod] public void CreateShouldThrowSshExceptionWhenMessageIsNotActivated() { const byte messageNumber = 60; const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; _sshMessageFactory.EnableAndActivateMessage(messageName); _sshMessageFactory.DisableAndDeactivateMessage(messageName); try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void CreateShouldReturnMessageInstanceCorrespondingToMessageNumberWhenMessageIsEnabledAndActivated() { const byte messageNumber = 60; const string messageName = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; _sshMessageFactory.EnableAndActivateMessage(messageName); var actual = _sshMessageFactory.Create(messageNumber); Assert.IsNotNull(actual); Assert.AreEqual(typeof (PasswordChangeRequiredMessage), actual.GetType()); _sshMessageFactory.DisableAndDeactivateMessage(messageName); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); actual = _sshMessageFactory.Create(messageNumber); Assert.IsNotNull(actual); Assert.AreEqual(typeof(InformationRequestMessage), actual.GetType()); } [TestMethod] public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsEnabled() { _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); try { _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message); } // verify that the original message remains enabled var actual = _sshMessageFactory.Create(60); Assert.IsNotNull(actual); Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); } [TestMethod] public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyDisabled() { const byte messageNumber = 60; _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); // verify that message remains disabled try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void DisableAndDeactivateMessageShouldNotThrowExceptionWhenMessageWasNeverEnabled() { const byte messageNumber = 60; _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); // verify that message is disabled try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void DisableAndDeactivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported() { const string messageName = "WHATEVER"; try { _sshMessageFactory.DisableAndDeactivateMessage("WHATEVER"); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message); } } [TestMethod] public void DisableAndDeactivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull() { const string messageName = null; try { _sshMessageFactory.DisableAndDeactivateMessage(messageName); Assert.Fail(); } catch (ArgumentNullException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual("messageName", ex.ParamName); } } [TestMethod] public void EnableAndActivateMessageShouldThrowSshExceptionWhenAnotherMessageWithSameMessageNumberIsAlreadyEnabled() { _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); try { _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_INFO_REQUEST'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'.", ex.Message); } // verify that the original message remains enabled var actual = _sshMessageFactory.Create(60); Assert.IsNotNull(actual); Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); } [TestMethod] public void EnableAndActivateMessageShouldNotThrowExceptionWhenMessageIsAlreadyEnabled() { _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); var actual = _sshMessageFactory.Create(60); Assert.IsNotNull(actual); Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); } [TestMethod] public void EnableAndActivateMessageShouldThrowSshExceptionWhenMessageIsNotSupported() { const string messageName = "WHATEVER"; try { _sshMessageFactory.EnableAndActivateMessage("WHATEVER"); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format("Message '{0}' is not supported.", messageName), ex.Message); } } [TestMethod] public void EnableAndActivateMessageShouldThrowArgumentNullExceptionWhenMessageNameIsNull() { const string messageName = null; try { _sshMessageFactory.EnableAndActivateMessage(messageName); Assert.Fail(); } catch (ArgumentNullException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual("messageName", ex.ParamName); } } [TestMethod] public void DisableNonKeyExchangeMessagesShouldDisableNonKeyExchangeMessages() { const byte messageNumber = 60; _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.DisableNonKeyExchangeMessages(); // verify that message is disabled try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void DisableNonKeyExchangeMessagesShouldNotDisableKeyExchangeMessages() { const byte messageNumber = 21; _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_NEWKEYS"); _sshMessageFactory.DisableNonKeyExchangeMessages(); // verify that message remains enabled var actual = _sshMessageFactory.Create(messageNumber); Assert.IsNotNull(actual); Assert.AreEqual(typeof (NewKeysMessage), actual.GetType()); } [TestMethod] public void EnableActivatedMessagesShouldEnableMessagesThatWereEnabledPriorToInvokingDisableNonKeyExchangeMessages() { const byte messageNumber = 60; _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.EnableActivatedMessages(); var actual = _sshMessageFactory.Create(messageNumber); Assert.IsNotNull(actual); Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); } [TestMethod] public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledPriorToInvokingDisableNonKeyExchangeMessages() { const byte messageNumber = 60; _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.EnableActivatedMessages(); try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void EnableActivatedMessagesShouldNotEnableMessagesThatWereDisabledAfterInvokingDisableNonKeyExchangeMessages() { const byte messageNumber = 60; _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.DisableAndDeactivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.EnableActivatedMessages(); try { _sshMessageFactory.Create(messageNumber); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid in the current context.", messageNumber), ex.Message); } } [TestMethod] public void EnableActivatedMessagesShouldThrowSshExceptionWhenAnothersMessageWithSameMessageNumberWasEnabledAfterInvokingDisableNonKeyExchangeMessages() { _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_INFO_REQUEST"); try { _sshMessageFactory.EnableActivatedMessages(); Assert.Fail(); } catch (SshException ex) { Assert.IsNull(ex.InnerException); Assert.AreEqual("Cannot enable message 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'. Message type 60 is already enabled for 'SSH_MSG_USERAUTH_INFO_REQUEST'.", ex.Message); } } [TestMethod] public void EnableActivatedMessagesShouldLeaveMessagesEnabledThatWereEnabledAfterInvokingDisableNonKeyExchangeMessages() { const byte messageNumber = 60; _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); _sshMessageFactory.EnableActivatedMessages(); var actual = _sshMessageFactory.Create(messageNumber); Assert.IsNotNull(actual); Assert.AreEqual(typeof(PasswordChangeRequiredMessage), actual.GetType()); } [TestMethod] public void HighestMessageNumberShouldCorrespondWithHighestSupportedMessageNumber() { var highestSupportMessageNumber = SshMessageFactory.AllMessages.Max(m => m.Number); Assert.AreEqual(highestSupportMessageNumber, SshMessageFactory.HighestMessageNumber); } [TestMethod] public void TotalMessageCountShouldBeTotalNumberOfSupportedMessages() { var totalNumberOfSupportedMessages = SshMessageFactory.AllMessages.Length; Assert.AreEqual(totalNumberOfSupportedMessages, SshMessageFactory.TotalMessageCount); } [TestMethod] [TestCategory("Performance")] public void Performance_Ctor() { const int runCount = 100000; // warm-up for (var i = 0; i < 3; i++) { var sshMessageFactory = new SshMessageFactory(); var sshMessageFactoryOriginal = new SshMessageFactoryOriginal(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < runCount; i++) { var sshMessageFactory = new SshMessageFactory(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); stopwatch.Reset(); stopwatch.Start(); for (var i = 0; i < runCount; i++) { var sshMessageFactory = new SshMessageFactoryOriginal(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); } [TestMethod] [TestCategory("LongRunning")] [TestCategory("Performance")] public void Performance_Create() { const int runCount = 10000000; const string messageName = "SSH_MSG_CHANNEL_CLOSE"; _sshMessageFactory.EnableAndActivateMessage(messageName); _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName); // warm-up for (var i = 0; i < 3; i++) { _sshMessageFactory.Create(97); _sshMessageFactoryOriginal.Create(97); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < runCount; i++) { var msg = _sshMessageFactory.Create(97); if (msg == null) Console.WriteLine(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); stopwatch.Reset(); stopwatch.Start(); for (var i = 0; i < runCount; i++) { var msg = _sshMessageFactoryOriginal.Create(97); if (msg == null) Console.WriteLine(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); } [TestMethod] [TestCategory("LongRunning")] [TestCategory("Performance")] public void Performance_EnableAndActivateMessage() { const int runCount = 1000000; const string messageName = "SSH_MSG_CHANNEL_CLOSE"; // warm-up for (var i = 0; i < 3; i++) { _sshMessageFactory.EnableAndActivateMessage(messageName); _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < runCount; i++) _sshMessageFactory.EnableAndActivateMessage(messageName); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); stopwatch.Reset(); stopwatch.Start(); for (var i = 0; i < runCount; i++) _sshMessageFactoryOriginal.EnableAndActivateMessage(messageName); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); } [TestMethod] [TestCategory("LongRunning")] [TestCategory("Performance")] public void Performance_DisableAndDeactivateMessage() { const int runCount = 1000000; const string messageName = "SSH_MSG_CHANNEL_CLOSE"; // warm-up for (var i = 0; i < 3; i++) { _sshMessageFactory.DisableAndDeactivateMessage(messageName); _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < runCount; i++) _sshMessageFactory.DisableAndDeactivateMessage(messageName); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); stopwatch.Reset(); stopwatch.Start(); for (var i = 0; i < runCount; i++) _sshMessageFactoryOriginal.DisableAndDeactivateMessage(messageName); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); } [TestMethod] [TestCategory("LongRunning")] [TestCategory("Performance")] public void Performance_DisableNonKeyExchangeMessages() { const int runCount = 1000000; _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER"); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_DEBUG"); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED"); _sshMessageFactory.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT"); _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_USERAUTH_BANNER"); _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_DEBUG"); _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_UNIMPLEMENTED"); _sshMessageFactoryOriginal.EnableAndActivateMessage("SSH_MSG_SERVICE_ACCEPT"); // warm-up for (var i = 0; i < 3; i++) { _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.EnableActivatedMessages(); _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages(); _sshMessageFactoryOriginal.EnableActivatedMessages(); } //Console.WriteLine("Starting test"); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < runCount; i++) { _sshMessageFactory.DisableNonKeyExchangeMessages(); _sshMessageFactory.EnableActivatedMessages(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); stopwatch.Reset(); stopwatch.Start(); for (var i = 0; i < runCount; i++) { _sshMessageFactoryOriginal.DisableNonKeyExchangeMessages(); _sshMessageFactoryOriginal.EnableActivatedMessages(); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); } internal class SshMessageFactoryOriginal { private readonly IEnumerable _messagesMetadata; public SshMessageFactoryOriginal() { _messagesMetadata = new[] { new MessageMetadata {Name = "SSH_MSG_NEWKEYS", Number = 21, Type = typeof(NewKeysMessage)}, new MessageMetadata { Name = "SSH_MSG_REQUEST_FAILURE", Number = 82, Type = typeof(RequestFailureMessage) }, new MessageMetadata {Name = "SSH_MSG_KEXINIT", Number = 20, Type = typeof(KeyExchangeInitMessage)}, new MessageMetadata { Name = "SSH_MSG_CHANNEL_OPEN_FAILURE", Number = 92, Type = typeof(ChannelOpenFailureMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_FAILURE", Number = 100, Type = typeof(ChannelFailureMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_EXTENDED_DATA", Number = 95, Type = typeof(ChannelExtendedDataMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_DATA", Number = 94, Type = typeof(ChannelDataMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_REQUEST", Number = 50, Type = typeof(RequestMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_REQUEST", Number = 98, Type = typeof(ChannelRequestMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_BANNER", Number = 53, Type = typeof(BannerMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_INFO_RESPONSE", Number = 61, Type = typeof(InformationResponseMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_FAILURE", Number = 51, Type = typeof(FailureMessage) }, new MessageMetadata {Name = "SSH_MSG_DEBUG", Number = 4, Type = typeof(DebugMessage),}, new MessageMetadata { Name = "SSH_MSG_KEXDH_INIT", Number = 30, Type = typeof(KeyExchangeDhInitMessage) }, new MessageMetadata { Name = "SSH_MSG_GLOBAL_REQUEST", Number = 80, Type = typeof(GlobalRequestMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_OPEN", Number = 90, Type = typeof(ChannelOpenMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", Number = 91, Type = typeof(ChannelOpenConfirmationMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_INFO_REQUEST", Number = 60, Type = typeof(InformationRequestMessage) }, new MessageMetadata { Name = "SSH_MSG_UNIMPLEMENTED", Number = 3, Type = typeof(UnimplementedMessage) }, new MessageMetadata { Name = "SSH_MSG_REQUEST_SUCCESS", Number = 81, Type = typeof(RequestSuccessMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_SUCCESS", Number = 99, Type = typeof(ChannelSuccessMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", Number = 60, Type = typeof(PasswordChangeRequiredMessage) }, new MessageMetadata {Name = "SSH_MSG_DISCONNECT", Number = 1, Type = typeof(DisconnectMessage)}, new MessageMetadata { Name = "SSH_MSG_SERVICE_REQUEST", Number = 5, Type = typeof(ServiceRequestMessage) }, new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_REQUEST", Number = 34, Type = typeof(KeyExchangeDhGroupExchangeRequest) }, new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_GROUP", Number = 31, Type = typeof(KeyExchangeDhGroupExchangeGroup) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_SUCCESS", Number = 52, Type = typeof(SuccessMessage) }, new MessageMetadata { Name = "SSH_MSG_USERAUTH_PK_OK", Number = 60, Type = typeof(PublicKeyMessage) }, new MessageMetadata {Name = "SSH_MSG_IGNORE", Number = 2, Type = typeof(IgnoreMessage)}, new MessageMetadata { Name = "SSH_MSG_CHANNEL_WINDOW_ADJUST", Number = 93, Type = typeof(ChannelWindowAdjustMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_EOF", Number = 96, Type = typeof(ChannelEofMessage) }, new MessageMetadata { Name = "SSH_MSG_CHANNEL_CLOSE", Number = 97, Type = typeof(ChannelCloseMessage) }, new MessageMetadata { Name = "SSH_MSG_SERVICE_ACCEPT", Number = 6, Type = typeof(ServiceAcceptMessage) }, new MessageMetadata { Name = "SSH_MSG_KEXDH_REPLY", Number = 31, Type = typeof(KeyExchangeDhReplyMessage) }, new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_INIT", Number = 32, Type = typeof(KeyExchangeDhGroupExchangeInit) }, new MessageMetadata { Name = "SSH_MSG_KEX_DH_GEX_REPLY", Number = 33, Type = typeof(KeyExchangeDhGroupExchangeReply) } }; } /// /// Disables and deactivate all messages. /// public void Reset() { foreach (var messageMetadata in _messagesMetadata) { messageMetadata.Activated = messageMetadata.Enabled = false; } } public void EnableActivatedMessages() { foreach (var messageMetadata in _messagesMetadata) { if (messageMetadata.Activated) messageMetadata.Enabled = true; } } public Message Create(byte messageNumber) { var messageMetadata = (from m in _messagesMetadata where m.Number == messageNumber && m.Enabled && m.Activated select m) .FirstOrDefault(); if (messageMetadata == null) throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.", messageNumber)); return messageMetadata.Type.CreateInstance(); } public void DisableNonKeyExchangeMessages() { foreach (var messageMetadata in _messagesMetadata) { if (messageMetadata.Activated && messageMetadata.Number > 2 && (messageMetadata.Number < 20 || messageMetadata.Number > 30)) { //Console.WriteLine("Disabling " + messageMetadata.Name + "..."); messageMetadata.Enabled = false; } } } public void EnableAndActivateMessage(string messageName) { lock (_messagesMetadata) { var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName); foreach (var messageMetadata in messagesMetadata) messageMetadata.Enabled = messageMetadata.Activated = true; } } public void DisableAndDeactivateMessage(string messageName) { lock (_messagesMetadata) { var messagesMetadata = _messagesMetadata.Where(m => m.Name == messageName); foreach (var messageMetadata in messagesMetadata) messageMetadata.Enabled = messageMetadata.Activated = false; } } private class MessageMetadata { public string Name { get; set; } public byte Number { get; set; } public bool Enabled { get; set; } public bool Activated { get; set; } public Type Type { get; set; } } } } }