ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Net.Sockets;
  7. using System.Text;
  8. using System.Threading;
  9. using Microsoft.Extensions.Logging.Abstractions;
  10. using Microsoft.VisualStudio.TestTools.UnitTesting;
  11. using Moq;
  12. using Renci.SshNet.Abstractions;
  13. using Renci.SshNet.Channels;
  14. using Renci.SshNet.Common;
  15. using Renci.SshNet.Tests.Common;
  16. namespace Renci.SshNet.Tests.Classes
  17. {
  18. [TestClass]
  19. public class ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound
  20. {
  21. private Mock<ISession> _sessionMock;
  22. private Mock<IConnectionInfo> _connectionInfoMock;
  23. private Mock<IChannelDirectTcpip> _channelMock;
  24. private ForwardedPortDynamic _forwardedPort;
  25. private IList<EventArgs> _closingRegister;
  26. private IList<ExceptionEventArgs> _exceptionRegister;
  27. private Exception _sessionException;
  28. private IPEndPoint _endpoint;
  29. private Socket _client;
  30. private IPEndPoint _remoteEndpoint;
  31. private string _userName;
  32. private TimeSpan _bindSleepTime;
  33. private ManualResetEvent _channelBindStarted;
  34. private ManualResetEvent _channelBindCompleted;
  35. [TestInitialize]
  36. public void Setup()
  37. {
  38. Arrange();
  39. Act();
  40. }
  41. [TestCleanup]
  42. public void Cleanup()
  43. {
  44. if (_client != null)
  45. {
  46. _client.Dispose();
  47. _client = null;
  48. }
  49. if (_forwardedPort != null)
  50. {
  51. _forwardedPort.Dispose();
  52. _forwardedPort = null;
  53. }
  54. if (_channelBindStarted != null)
  55. {
  56. _channelBindStarted.Dispose();
  57. _channelBindStarted = null;
  58. }
  59. if (_channelBindCompleted != null)
  60. {
  61. _channelBindCompleted.Dispose();
  62. _channelBindCompleted = null;
  63. }
  64. }
  65. private void CreateMocks()
  66. {
  67. _connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
  68. _sessionMock = new Mock<ISession>(MockBehavior.Strict);
  69. _sessionMock.Setup(p => p.SessionLoggerFactory).Returns(NullLoggerFactory.Instance);
  70. _channelMock = new Mock<IChannelDirectTcpip>(MockBehavior.Strict);
  71. }
  72. private void SetupData()
  73. {
  74. var random = new Random();
  75. _closingRegister = new List<EventArgs>();
  76. _exceptionRegister = new List<ExceptionEventArgs>();
  77. _endpoint = new IPEndPoint(IPAddress.Loopback, 8122);
  78. _remoteEndpoint = new IPEndPoint(IPAddress.Parse("193.168.1.5"), random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort));
  79. _bindSleepTime = TimeSpan.FromMilliseconds(random.Next(100, 500));
  80. _userName = random.Next().ToString(CultureInfo.InvariantCulture);
  81. _forwardedPort = new ForwardedPortDynamic(_endpoint.Address.ToString(), (uint)_endpoint.Port);
  82. _sessionException = new Exception();
  83. _channelBindStarted = new ManualResetEvent(false);
  84. _channelBindCompleted = new ManualResetEvent(false);
  85. _forwardedPort.Closing += (sender, args) => _closingRegister.Add(args);
  86. _forwardedPort.Exception += (sender, args) => _exceptionRegister.Add(args);
  87. _forwardedPort.Session = _sessionMock.Object;
  88. _client = new Socket(_endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
  89. {
  90. ReceiveTimeout = 100,
  91. SendTimeout = 100,
  92. SendBufferSize = 0
  93. };
  94. }
  95. private void SetupMocks()
  96. {
  97. _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(15));
  98. _sessionMock.Setup(p => p.IsConnected).Returns(true);
  99. _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object);
  100. _sessionMock.Setup(p => p.CreateChannelDirectTcpip()).Returns(_channelMock.Object);
  101. _channelMock.Setup(p => p.Open(_remoteEndpoint.Address.ToString(), (uint)_remoteEndpoint.Port, _forwardedPort, It.IsAny<Socket>()));
  102. _channelMock.Setup(p => p.IsOpen).Returns(true);
  103. _channelMock.Setup(p => p.Bind()).Callback(() =>
  104. {
  105. _channelBindStarted.Set();
  106. Thread.Sleep(_bindSleepTime);
  107. _channelBindCompleted.Set();
  108. });
  109. _channelMock.Setup(p => p.Dispose());
  110. }
  111. protected void Arrange()
  112. {
  113. CreateMocks();
  114. SetupData();
  115. SetupMocks();
  116. // start port
  117. _forwardedPort.Start();
  118. // connect to port
  119. EstablishSocks4Connection(_client);
  120. // wait until SOCKS client is bound to channel
  121. Assert.IsTrue(_channelBindStarted.WaitOne(TimeSpan.FromMilliseconds(200)));
  122. }
  123. protected void Act()
  124. {
  125. _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(_sessionException));
  126. }
  127. [TestMethod]
  128. public void ShouldBlockUntilBindHasCompleted()
  129. {
  130. Assert.IsTrue(_channelBindCompleted.WaitOne(0));
  131. }
  132. [TestMethod]
  133. public void IsStartedShouldReturnFalse()
  134. {
  135. Assert.IsFalse(_forwardedPort.IsStarted);
  136. }
  137. [TestMethod]
  138. public void ForwardedPortShouldRefuseNewConnections()
  139. {
  140. using (var client = new Socket(_endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
  141. {
  142. try
  143. {
  144. client.Connect(_endpoint);
  145. Assert.Fail();
  146. }
  147. catch (SocketException ex)
  148. {
  149. Assert.AreEqual(SocketError.ConnectionRefused, ex.SocketErrorCode);
  150. }
  151. }
  152. }
  153. [TestMethod]
  154. public void BoundClientShouldNotBeClosed()
  155. {
  156. // the forwarded port itself does not close the client connection; when the channel is closed properly
  157. // it's the channel that will take care of closing the client connection
  158. //
  159. // we'll check if the client connection is still alive by attempting to receive, which should time out
  160. // as the forwarded port (or its channel) are not sending anything
  161. var buffer = new byte[1];
  162. try
  163. {
  164. _client.Receive(buffer);
  165. Assert.Fail();
  166. }
  167. catch (SocketException ex)
  168. {
  169. Assert.AreEqual(SocketError.TimedOut, ex.SocketErrorCode);
  170. }
  171. }
  172. [TestMethod]
  173. public void ClosingShouldHaveFiredOnce()
  174. {
  175. Assert.AreEqual(1, _closingRegister.Count);
  176. }
  177. [TestMethod]
  178. public void ExceptionShouldHaveFiredOne()
  179. {
  180. Assert.AreEqual(1, _exceptionRegister.Count, _exceptionRegister.AsString());
  181. Assert.IsNotNull(_exceptionRegister[0], _exceptionRegister.AsString());
  182. Assert.AreSame(_sessionException, _exceptionRegister[0].Exception, _exceptionRegister.AsString());
  183. }
  184. [TestMethod]
  185. public void OpenOnChannelShouldBeInvokedOnce()
  186. {
  187. _channelMock.Verify(
  188. p =>
  189. p.Open(_remoteEndpoint.Address.ToString(), (uint)_remoteEndpoint.Port, _forwardedPort,
  190. It.IsAny<Socket>()), Times.Once);
  191. }
  192. [TestMethod]
  193. public void BindOnChannelShouldBeInvokedOnce()
  194. {
  195. _channelMock.Verify(p => p.Bind(), Times.Once);
  196. }
  197. [TestMethod]
  198. public void DisposeOnChannelShouldBeInvokedOnce()
  199. {
  200. _channelMock.Verify(p => p.Dispose(), Times.Once);
  201. }
  202. private void EstablishSocks4Connection(Socket client)
  203. {
  204. var userNameBytes = Encoding.ASCII.GetBytes(_userName);
  205. var addressBytes = _remoteEndpoint.Address.GetAddressBytes();
  206. var portBytes = BitConverter.GetBytes((ushort)_remoteEndpoint.Port).Reverse().ToArray();
  207. _client.Connect(_endpoint);
  208. // send SOCKS version
  209. client.Send(new byte[] { 0x04 }, 0, 1, SocketFlags.None);
  210. // send command byte
  211. client.Send(new byte[] { 0x00 }, 0, 1, SocketFlags.None);
  212. // send port
  213. client.Send(portBytes, 0, portBytes.Length, SocketFlags.None);
  214. // send address
  215. client.Send(addressBytes, 0, addressBytes.Length, SocketFlags.None);
  216. // send user name
  217. client.Send(userNameBytes, 0, userNameBytes.Length, SocketFlags.None);
  218. // terminate user name with null
  219. client.Send(new byte[] { 0x00 }, 0, 1, SocketFlags.None);
  220. var buffer = new byte[8];
  221. var bytesRead = SocketAbstraction.Read(client, buffer, 0, buffer.Length, TimeSpan.FromMilliseconds(500));
  222. Assert.AreEqual(buffer.Length, bytesRead);
  223. }
  224. }
  225. }