| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 | using Renci.SshNet.Common;using Renci.SshNet.IntegrationTests.Common;using Renci.SshNet.Messages.Transport;namespace Renci.SshNet.IntegrationTests{    [TestClass]    public class ConnectivityTests : IntegrationTestBase    {        private AuthenticationMethodFactory _authenticationMethodFactory;        private IConnectionInfoFactory _connectionInfoFactory;        private IConnectionInfoFactory _adminConnectionInfoFactory;        private RemoteSshdConfig _remoteSshdConfig;        private SshConnectionDisruptor _sshConnectionDisruptor;        [TestInitialize]        public void SetUp()        {            _authenticationMethodFactory = new AuthenticationMethodFactory();            _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort, _authenticationMethodFactory);            _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort);            _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig();            _sshConnectionDisruptor = new SshConnectionDisruptor(_adminConnectionInfoFactory);        }        [TestCleanup]        public void TearDown()        {            _remoteSshdConfig?.Reset();        }        [TestMethod]        public void Common_CreateMoreChannelsThanMaxSessions()        {            var connectionInfo = _connectionInfoFactory.Create();            connectionInfo.MaxSessions = 2;            using (var client = new SshClient(connectionInfo))            {                client.Connect();                // create one more channel than the maximum number of sessions                // as that would block indefinitely when creating the last channel                // if the channel would not be properly closed                for (var i = 0; i < connectionInfo.MaxSessions + 1; i++)                {                    using (var stream = client.CreateShellStream("vt220", 20, 20, 20, 20, 20))                    {                        stream.WriteLine("echo test");                        stream.ReadLine();                    }                }            }        }        [TestMethod]        public void Common_DisposeAfterLossOfNetworkConnectivity()        {            var hostNetworkConnectionDisabled = false;            SshConnectionRestorer disruptor = null;            try            {                Exception errorOccurred = null;                int count = 0;                using (var client = new SftpClient(_connectionInfoFactory.Create()))                {                    client.ErrorOccurred += (sender, args) =>                                                {                                                    Console.WriteLine("Exception " + count++);                                                    Console.WriteLine(args.Exception);                                                    errorOccurred = args.Exception;                                                };                    client.Connect();                    disruptor = _sshConnectionDisruptor.BreakConnections();                    hostNetworkConnectionDisabled = true;                    WaitForConnectionInterruption(client);                }                                Assert.IsNotNull(errorOccurred);                Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType());                var connectionException = (SshConnectionException) errorOccurred;                Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason);                Assert.IsNull(connectionException.InnerException);                Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message);            }            finally            {                if (hostNetworkConnectionDisabled)                {                    disruptor?.RestoreConnections();                    disruptor?.Dispose();                }            }        }        [TestMethod]        public void Common_DetectLossOfNetworkConnectivityThroughKeepAlive()        {            using (var client = new SftpClient(_connectionInfoFactory.Create()))            {                Exception errorOccurred = null;                int count = 0;                client.ErrorOccurred += (sender, args) =>                                            {                                                Console.WriteLine("Exception "+ count++);                                                Console.WriteLine(args.Exception);                                                errorOccurred = args.Exception;                                            };                client.KeepAliveInterval = new TimeSpan(0, 0, 0, 0, 50);                client.Connect();                var disruptor = _sshConnectionDisruptor.BreakConnections();                try                {                    WaitForConnectionInterruption(client);                    Assert.IsFalse(client.IsConnected);                    Assert.IsNotNull(errorOccurred);                    Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType());                    var connectionException = (SshConnectionException) errorOccurred;                    Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason);                    Assert.IsNull(connectionException.InnerException);                    Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message);                }                finally                {                    disruptor?.RestoreConnections();                    disruptor?.Dispose();                }            }        }        private static void WaitForConnectionInterruption(SftpClient client)        {            for (var i = 0; i < 500; i++)            {                if (!client.IsConnected)                {                    break;                }                Thread.Sleep(100);            }            // After interruption, you have to wait for the events to propagate.            Thread.Sleep(100);        }        [TestMethod]        public void Common_DetectConnectionResetThroughSftpInvocation()        {            using (var client = new SftpClient(_connectionInfoFactory.Create()))            {                client.KeepAliveInterval = TimeSpan.FromSeconds(1);                client.OperationTimeout = TimeSpan.FromSeconds(60);                ManualResetEvent errorOccurredSignaled = new ManualResetEvent(false);                Exception errorOccurred = null;                client.ErrorOccurred += (sender, args) =>                {                    errorOccurred = args.Exception;                    errorOccurredSignaled.Set();                };                client.Connect();                var disruptor = _sshConnectionDisruptor.BreakConnections();                try                {                    client.ListDirectory("/");                    Assert.Fail();                }                catch (SshConnectionException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("Client not connected.", ex.Message);                    Assert.IsNotNull(errorOccurred);                    Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType());                    var connectionException = (SshConnectionException) errorOccurred;                    Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason);                    Assert.IsNull(connectionException.InnerException);                    Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message);                }                finally                {                    disruptor.RestoreConnections();                    disruptor.Dispose();                }            }        }        [TestMethod]        public void Common_LossOfNetworkConnectivityDisconnectAndConnect()        {            bool vmNetworkConnectionDisabled = false;            SshConnectionRestorer disruptor = null;            try            {                using (var client = new SftpClient(_connectionInfoFactory.Create()))                {                    Exception errorOccurred = null;                    client.ErrorOccurred += (sender, args) => errorOccurred = args.Exception;                    client.Connect();                    disruptor = _sshConnectionDisruptor.BreakConnections();                    vmNetworkConnectionDisabled = true;                    WaitForConnectionInterruption(client);                    // disconnect while network connectivity is lost                    client.Disconnect();                    Assert.IsFalse(client.IsConnected);                    disruptor.RestoreConnections();                    vmNetworkConnectionDisabled = false;                    // connect when network connectivity is restored                    client.Connect();                    client.ChangeDirectory(client.WorkingDirectory);                    client.Dispose();                    Assert.IsNotNull(errorOccurred);                    Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType());                    var connectionException = (SshConnectionException) errorOccurred;                    Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason);                    Assert.IsNull(connectionException.InnerException);                    Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message);                }            }            finally            {                if (vmNetworkConnectionDisabled)                {                    disruptor.RestoreConnections();                }                disruptor?.Dispose();            }        }        [TestMethod]        public void Common_DetectLossOfNetworkConnectivityThroughSftpInvocation()        {            using (var client = new SftpClient(_connectionInfoFactory.Create()))            {                ManualResetEvent errorOccurredSignaled = new ManualResetEvent(false);                Exception errorOccurred = null;                client.ErrorOccurred += (sender, args) =>                {                    errorOccurred = args.Exception;                    errorOccurredSignaled.Set();                };                client.Connect();                var disruptor = _sshConnectionDisruptor.BreakConnections();                Thread.Sleep(100);                try                {                    client.ListDirectory("/");                    Assert.Fail();                }                catch (SshConnectionException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("Client not connected.", ex.Message);                    Assert.IsNotNull(errorOccurred);                    Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType());                    var connectionException = (SshConnectionException) errorOccurred;                    Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason);                    Assert.IsNull(connectionException.InnerException);                    Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message);                }                finally                {                    disruptor.RestoreConnections();                    disruptor.Dispose();                }            }        }        [TestMethod]        public void Common_DetectSessionKilledOnServer()        {            using (var client = new SftpClient(_connectionInfoFactory.Create()))            {                ManualResetEvent errorOccurredSignaled = new ManualResetEvent(false);                Exception errorOccurred = null;                client.ErrorOccurred += (sender, args) =>                {                    errorOccurred = args.Exception;                    errorOccurredSignaled.Set();                };                client.Connect();                // Kill the server session                using (var adminClient = new SshClient(_adminConnectionInfoFactory.Create()))                {                    adminClient.Connect();                    var command = $"sudo ps --no-headers -u {client.ConnectionInfo.Username} -f | grep \"{client.ConnectionInfo.Username}@notty\" | awk '{{print $2}}' | xargs sudo kill -9";                    var sshCommand = adminClient.CreateCommand(command);                    var result = sshCommand.Execute();                    Assert.AreEqual(0, sshCommand.ExitStatus, sshCommand.Error);                }                Assert.IsTrue(errorOccurredSignaled.WaitOne(200));                Assert.IsNotNull(errorOccurred);                Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType());                Assert.IsNull(errorOccurred.InnerException);                Assert.AreEqual("An established connection was aborted by the server.", errorOccurred.Message);                Assert.IsFalse(client.IsConnected);            }        }        [TestMethod]        public void Common_HostKeyValidation_Failure()        {            using (var client = new SshClient(_connectionInfoFactory.Create()))            {                client.HostKeyReceived += (sender, e) => { e.CanTrust = false; };                try                {                    client.Connect();                    Assert.Fail();                }                catch (SshConnectionException ex)                {                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("Key exchange negotiation failed.", ex.Message);                }            }        }        [TestMethod]        public void Common_HostKeyValidation_Success()        {            byte[] host_rsa_key_openssh_fingerprint =                {                    0x3d, 0x90, 0xd8, 0x0d, 0xd5, 0xe0, 0xb6, 0x13,                    0x42, 0x7c, 0x78, 0x1e, 0x19, 0xa3, 0x99, 0x2b                };            var hostValidationSuccessful = false;            using (var client = new SshClient(_connectionInfoFactory.Create()))            {                client.HostKeyReceived += (sender, e) =>                {                    if (host_rsa_key_openssh_fingerprint.Length == e.FingerPrint.Length)                    {                        for (var i = 0; i < host_rsa_key_openssh_fingerprint.Length; i++)                        {                            if (host_rsa_key_openssh_fingerprint[i] != e.FingerPrint[i])                            {                                e.CanTrust = false;                                break;                            }                        }                        hostValidationSuccessful = e.CanTrust;                    }                    else                    {                        e.CanTrust = false;                    }                };                client.Connect();            }            Assert.IsTrue(hostValidationSuccessful);        }        [TestMethod]        public void Common_HostKeyValidationSHA256_Success()        {            var hostValidationSuccessful = false;            using (var client = new SshClient(_connectionInfoFactory.Create()))            {                client.HostKeyReceived += (sender, e) =>                {                    if (e.FingerPrintSHA256 == "9fa6vbz64gimzsGZ/xZi3aaYE1o7E96iU2NjcfQNGwI")                    {                        hostValidationSuccessful = e.CanTrust;                    }                    else                    {                        e.CanTrust = false;                    }                };                client.Connect();            }            Assert.IsTrue(hostValidationSuccessful);        }        [TestMethod]        public void Common_HostKeyValidationMD5_Success()        {            var hostValidationSuccessful = false;            using (var client = new SshClient(_connectionInfoFactory.Create()))            {                client.HostKeyReceived += (sender, e) =>                {                    if (e.FingerPrintMD5 == "3d:90:d8:0d:d5:e0:b6:13:42:7c:78:1e:19:a3:99:2b")                    {                        hostValidationSuccessful = e.CanTrust;                    }                    else                    {                        e.CanTrust = false;                    }                };                client.Connect();            }            Assert.IsTrue(hostValidationSuccessful);        }        /// <summary>        /// Verifies whether we handle a disconnect initiated by the SSH server (through a SSH_MSG_DISCONNECT message).        /// </summary>        /// <remarks>        /// We force this by only configuring <c>keyboard-interactive</c> as authentication method, while <c>ChallengeResponseAuthentication</c>        /// is not enabled.  This causes OpenSSH to terminate the connection because there are no authentication methods left.        /// </remarks>        [TestMethod]        public void Common_ServerRejectsConnection()        {            _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive")                             .Update()                             .Restart();            var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserKeyboardInteractiveAuthenticationMethod());            using (var client = new SftpClient(connectionInfo))            {                try                {                    client.Connect();                    Assert.Fail();                }                catch (SshConnectionException ex)                {                    Assert.AreEqual(DisconnectReason.ProtocolError, ex.DisconnectReason);                    Assert.IsNull(ex.InnerException);                    Assert.AreEqual("The connection was closed by the server: no authentication methods enabled (ProtocolError).", ex.Message);                }            }        }    }}
 |