diff --git a/docker/DockerFile b/docker/DockerFile
index 9c8f0cd..65221db 100644
--- a/docker/DockerFile
+++ b/docker/DockerFile
@@ -33,7 +33,11 @@ RUN apk add --no-cache syslog-ng && \
addgroup sshnetadm sudo && \
dos2unix /opt/sshnet/* && \
# install shadow package; we use chage command in this package to expire/unexpire password of the sshnet user
- apk add --no-cache shadow
+ apk add --no-cache shadow && \
+ # allow us to use telnet command; we use this in the remote port forwarding tests
+ apk --no-cache add busybox-extras && \
+ # install full-fledged ps command
+ apk add --no-cache procps
EXPOSE 22 22
diff --git a/src/SshNetTests/Common/RemoteSshdConfigExtensions.cs b/src/SshNetTests/Common/RemoteSshdConfigExtensions.cs
index 9c66efb..6869127 100644
--- a/src/SshNetTests/Common/RemoteSshdConfigExtensions.cs
+++ b/src/SshNetTests/Common/RemoteSshdConfigExtensions.cs
@@ -11,6 +11,7 @@ public static void Reset(this RemoteSshdConfig remoteSshdConfig)
remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, DefaultAuthenticationMethods)
.WithChallengeResponseAuthentication(false)
.WithKeyboardInteractiveAuthentication(false)
+ .PrintMotd()
.WithLogLevel(LogLevel.Debug3)
.ClearHostKeyFiles()
.AddHostKeyFile(HostKeyFile.Rsa.FilePath)
diff --git a/src/SshNetTests/PrivateKeyAuthenticationTests.cs b/src/SshNetTests/PrivateKeyAuthenticationTests.cs
index d0225ab..587db7e 100644
--- a/src/SshNetTests/PrivateKeyAuthenticationTests.cs
+++ b/src/SshNetTests/PrivateKeyAuthenticationTests.cs
@@ -1,5 +1,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet;
+using SshNet.TestTools.OpenSSH;
using SshNetTests.Common;
namespace SshNetTests
@@ -29,22 +30,46 @@ public void TearDown()
[TestMethod]
public void Ecdsa256()
{
+ _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp256)
+ .Update()
+ .Restart();
+
var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_256_openssh"));
using (var client = new SshClient(connectionInfo))
{
client.Connect();
- client.Disconnect();
}
}
+ [TestMethod]
public void Ecdsa384()
{
+ _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp384)
+ .Update()
+ .Restart();
+ var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_384_openssh"));
+
+ using (var client = new SshClient(connectionInfo))
+ {
+ client.Connect();
+ }
}
+ [TestMethod]
public void EcdsaA521()
{
+ _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp521)
+ .Update()
+ .Restart();
+
+ var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_521_openssh"));
+
+ using (var client = new SshClient(connectionInfo))
+ {
+ client.Connect();
+ }
}
private PrivateKeyAuthenticationMethod CreatePrivateKeyAuthenticationMethod(string keyResource)
diff --git a/src/SshNetTests/RemoteSshd.cs b/src/SshNetTests/RemoteSshd.cs
index 7652f65..5f530ab 100644
--- a/src/SshNetTests/RemoteSshd.cs
+++ b/src/SshNetTests/RemoteSshd.cs
@@ -102,6 +102,32 @@ public RemoteSshdConfig WithKeyboardInteractiveAuthentication(bool value)
return this;
}
+ ///
+ /// Specifies whether sshd should print /etc/motd when a user logs in interactively.
+ ///
+ /// if sshd should print /etc/motd when a user logs in interactively.
+ ///
+ /// The current instance.
+ ///
+ public RemoteSshdConfig PrintMotd(bool? value = true)
+ {
+ _config.PrintMotd = value;
+ return this;
+ }
+
+ ///
+ /// Specifies whether TCP forwarding is permitted.
+ ///
+ /// to allow TCP forwarding.
+ ///
+ /// The current instance.
+ ///
+ public RemoteSshdConfig AllowTcpForwarding(bool? value = true)
+ {
+ _config.AllowTcpForwarding = value;
+ return this;
+ }
+
public RemoteSshdConfig WithAuthenticationMethods(string user, string authenticationMethods)
{
var sshNetMatch = _config.Matches.FirstOrDefault(m => m.Users.Contains(user));
diff --git a/src/SshNetTests/SftpTests.cs b/src/SshNetTests/SftpTests.cs
index c203a31..733250a 100644
--- a/src/SshNetTests/SftpTests.cs
+++ b/src/SshNetTests/SftpTests.cs
@@ -4846,8 +4846,220 @@ public void Sftp_Open_Append_Write_FileDoesNotExist()
}
}
+
+
+ [TestMethod]
+ public void Sftp_Open_PathAndMode_ModeIsCreate_FileDoesNotExist()
+ {
+ const string remoteFile = "/home/sshnet/test";
+
+ using (var client = new SftpClient(_connectionInfoFactory.Create()))
+ {
+ client.Connect();
+
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+
+ try
+ {
+ #region Verify if merely opening the file for create creates a zero-byte file
+
+ using (client.Open(remoteFile, FileMode.Create))
+ {
+ }
+
+ Assert.IsTrue(client.Exists(remoteFile));
+
+ var attributes = client.GetAttributes(remoteFile);
+ Assert.IsTrue(attributes.IsRegularFile);
+ Assert.AreEqual(0L, attributes.Size);
+
+ #endregion Verify if merely opening the file for create creates a zero-byte file
+
+ client.DeleteFile(remoteFile);
+
+ #region Verify if content is actually written to the file
+
+ var content = GenerateRandom(100);
+
+ using (var s = client.Open(remoteFile, FileMode.Create))
+ {
+ s.Write(content, 0, content.Length);
+ }
+
+ using (var downloaded = new MemoryStream())
+ {
+ client.DownloadFile(remoteFile, downloaded);
+ downloaded.Position = 0;
+ Assert.AreEqual(CreateHash(content), CreateHash(downloaded));
+ }
+
+ #endregion Verify if content is actually written to the file
+ }
+ finally
+ {
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+ }
+ }
+ }
+
+ [TestMethod]
+ public void Sftp_Open_PathAndMode_ModeIsCreate_ExistingFile()
+ {
+ const string remoteFile = "/home/sshnet/test";
+ const int fileSize = 5 * 1024;
+ var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b };
+
+ using (var client = new SftpClient(_connectionInfoFactory.Create()))
+ using (var input = CreateMemoryStream(fileSize))
+ {
+ client.Connect();
+
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+
+ try
+ {
+ input.Position = 0;
+ client.UploadFile(input, remoteFile);
+
+ using (var stream = client.Open(remoteFile, FileMode.Create))
+ {
+ // Verify if merely opening the file for create overwrites the file
+ var attributes = client.GetAttributes(remoteFile);
+ Assert.IsTrue(attributes.IsRegularFile);
+ Assert.AreEqual(0L, attributes.Size);
+
+ stream.Write(newContent, 0, newContent.Length);
+ stream.Position = 0;
+
+ Assert.AreEqual(CreateHash(newContent), CreateHash(stream));
+ }
+ }
+ finally
+ {
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+ }
+ }
+ }
+
+ [TestMethod]
+ public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsReadWrite_FileDoesNotExist()
+ {
+ const string remoteFile = "/home/sshnet/test";
+
+ using (var client = new SftpClient(_connectionInfoFactory.Create()))
+ {
+ client.Connect();
+
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+
+ try
+ {
+ #region Verify if merely opening the file for create creates a zero-byte file
+
+ using (client.Open(remoteFile, FileMode.Create, FileAccess.ReadWrite))
+ {
+ }
+
+ Assert.IsTrue(client.Exists(remoteFile));
+
+ var attributes = client.GetAttributes(remoteFile);
+ Assert.IsTrue(attributes.IsRegularFile);
+ Assert.AreEqual(0L, attributes.Size);
+
+ #endregion Verify if merely opening the file for create creates a zero-byte file
+
+ client.DeleteFile(remoteFile);
+
+ #region Verify if content is actually written to the file
+
+ var content = GenerateRandom(100);
+
+ using (var s = client.Open(remoteFile, FileMode.Create, FileAccess.ReadWrite))
+ {
+ s.Write(content, 0, content.Length);
+ }
+
+ using (var downloaded = new MemoryStream())
+ {
+ client.DownloadFile(remoteFile, downloaded);
+ downloaded.Position = 0;
+ Assert.AreEqual(CreateHash(content), CreateHash(downloaded));
+ }
+
+ #endregion Verify if content is actually written to the file
+ }
+ finally
+ {
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+ }
+ }
+ }
+
+ [TestMethod]
+ public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsReadWrite_ExistingFile()
+ {
+ const string remoteFile = "/home/sshnet/test";
+ const int fileSize = 5 * 1024;
+ var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b };
+
+ using (var client = new SftpClient(_connectionInfoFactory.Create()))
+ using (var input = CreateMemoryStream(fileSize))
+ {
+ client.Connect();
+
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+
+ try
+ {
+ input.Position = 0;
+ client.UploadFile(input, remoteFile);
+
+ using (var stream = client.Open(remoteFile, FileMode.Create, FileAccess.ReadWrite))
+ {
+ // Verify if merely opening the file for create overwrites the file
+ var attributes = client.GetAttributes(remoteFile);
+ Assert.IsTrue(attributes.IsRegularFile);
+ Assert.AreEqual(0L, attributes.Size);
+
+ stream.Write(newContent, 0, newContent.Length);
+ stream.Position = 0;
+
+ Assert.AreEqual(CreateHash(newContent), CreateHash(stream));
+ }
+ }
+ finally
+ {
+ if (client.Exists(remoteFile))
+ {
+ client.DeleteFile(remoteFile);
+ }
+ }
+ }
+ }
+
[TestMethod]
- public void Sftp_Open_Create_Write_ExistingFile()
+ public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsWrite_ExistingFile()
{
const string remoteFile = "/home/sshnet/test";
@@ -4893,7 +5105,7 @@ public void Sftp_Open_Create_Write_ExistingFile()
}
[TestMethod]
- public void Sftp_Open_Create_Write_FileDoesNotExist()
+ public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsWrite_FileDoesNotExist()
{
const string remoteFile = "/home/sshnet/test";
diff --git a/src/SshNetTests/SshTests.cs b/src/SshNetTests/SshTests.cs
index c3af625..fcccbc8 100644
--- a/src/SshNetTests/SshTests.cs
+++ b/src/SshNetTests/SshTests.cs
@@ -1,6 +1,8 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet;
+using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
+using SshNetTests.Common;
using System;
using System.Collections.Generic;
using System.IO;
@@ -17,12 +19,25 @@ public class SshTests : TestBase
{
private IConnectionInfoFactory _connectionInfoFactory;
private IConnectionInfoFactory _adminConnectionInfoFactory;
+ private RemoteSshdConfig _remoteSshdConfig;
[TestInitialize]
public void SetUp()
{
_connectionInfoFactory = new LinuxVMConnectionFactory();
_adminConnectionInfoFactory = new LinuxAdminConnectionFactory();
+
+ _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig();
+ _remoteSshdConfig.AllowTcpForwarding()
+ .PrintMotd(false)
+ .Update()
+ .Restart();
+ }
+
+ [TestCleanup]
+ public void TearDown()
+ {
+ _remoteSshdConfig?.Reset();
}
///
@@ -35,8 +50,14 @@ public void Ssh_ShellStream_Exit()
{
client.Connect();
- using (var shellStream = client.CreateShellStream("xterm", 80, 24, 800, 600, 1024))
+ var terminalModes = new Dictionary
+ {
+ { TerminalModes.ECHO, 0 }
+ };
+
+ using (var shellStream = client.CreateShellStream("xterm", 80, 24, 800, 600, 1024, terminalModes))
{
+ shellStream.WriteLine("echo Hello!");
shellStream.WriteLine("exit");
Thread.Sleep(1000);
@@ -55,13 +76,13 @@ public void Ssh_ShellStream_Exit()
var line = shellStream.ReadLine();
Assert.IsNotNull(line);
- Assert.IsTrue(line.Contains("exit"), line);
+ Assert.IsTrue(line.EndsWith("Hello!"), line);
- // TODO: ReadLine should immediately return null when the channel has been closed (issue #672)
+ // TODO: ReadLine should return null when the buffer is empty and the channel has been closed (issue #672)
try
{
- shellStream.ReadLine();
- Assert.Fail();
+ line = shellStream.ReadLine();
+ Assert.Fail(line);
}
catch (NullReferenceException)
{
@@ -71,6 +92,72 @@ public void Ssh_ShellStream_Exit()
}
}
+ ///
+ /// https://github.com/sshnet/SSH.NET/issues/63
+ ///
+ [TestMethod]
+ public void Ssh_ShellStream_IntermittendOutput()
+ {
+ const string remoteFile = "/home/sshnet/test.sh";
+
+ var expectedResult = string.Join("\n",
+ "Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "Line 5 ",
+ "Line 6");
+
+ var scriptBuilder = new StringBuilder();
+ scriptBuilder.Append("#!/bin/sh\n");
+ scriptBuilder.Append("echo Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
+ scriptBuilder.Append("sleep .5\n");
+ scriptBuilder.Append("echo Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
+ scriptBuilder.Append("echo Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
+ scriptBuilder.Append("echo Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
+ scriptBuilder.Append("sleep 2\n");
+ scriptBuilder.Append("echo \"Line 5 \"\n");
+ scriptBuilder.Append("echo Line 6 \n");
+ scriptBuilder.Append("exit 13\n");
+
+ using (var sshClient = new SshClient(_connectionInfoFactory.Create()))
+ {
+ sshClient.Connect();
+
+ CreateShellScript(_connectionInfoFactory, remoteFile, scriptBuilder.ToString());
+
+ try
+ {
+ var terminalModes = new Dictionary
+ {
+ { TerminalModes.ECHO, 0 }
+ };
+
+ using (var shellStream = sshClient.CreateShellStream("xterm", 80, 24, 800, 600, 1024, terminalModes))
+ {
+ shellStream.WriteLine(remoteFile);
+
+ using (var reader = new StreamReader(shellStream, new UTF8Encoding(false), false, 10))
+ {
+ var lines = new List();
+ string line = null;
+ while ((line = reader.ReadLine()) != null)
+ {
+ lines.Add(line);
+ }
+
+ Assert.AreEqual(6, lines.Count, string.Join("\n", lines));
+ Assert.AreEqual(expectedResult, string.Join("\n", lines));
+ }
+ }
+ }
+ finally
+ {
+ RemoveFileOrDirectory(sshClient, remoteFile);
+ }
+ }
+ }
+
///
/// Issue 1555
///
@@ -176,8 +263,7 @@ public void Ssh_Command_IntermittendOutput_OutputStream()
"Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Line 5 ",
- "Line 6",
- "");
+ "Line 6");
var scriptBuilder = new StringBuilder();
scriptBuilder.Append("#!/bin/sh\n");
@@ -241,10 +327,9 @@ public void Ssh_Command_IntermittendOutput_OutputStream()
public void Ssh_DynamicPortForwarding_DisposeSshClientWithoutStoppingPort()
{
const string searchText = "HTTP/1.1 301 Moved Permanently";
- const string hostName = "www.amazon.com";
+ const string hostName = "github.com";
- var httpGetRequest = Encoding.ASCII.GetBytes($"GET /null HTTP/1.1\r\nHost: {hostName}\r\n\r\n");
- var httpResponseBuffer = new byte[2048];
+ var httpGetRequest = Encoding.ASCII.GetBytes($"GET / HTTP/1.1\r\nHost: {hostName}\r\n\r\n");
Socket socksSocket;
using (var client = new SshClient(_connectionInfoFactory.Create()))
@@ -253,7 +338,7 @@ public void Ssh_DynamicPortForwarding_DisposeSshClientWithoutStoppingPort()
client.Connect();
var forwardedPort = new ForwardedPortDynamic(1080);
- forwardedPort.Exception += (sender, args) => Console.WriteLine("BROL" + args.Exception.ToString());
+ forwardedPort.Exception += (sender, args) => Console.WriteLine(args.Exception.ToString());
client.AddForwardedPort(forwardedPort);
forwardedPort.Start();
@@ -264,37 +349,28 @@ public void Ssh_DynamicPortForwarding_DisposeSshClientWithoutStoppingPort()
socksSocket = socksClient.Connect(hostName, 80);
socksSocket.Send(httpGetRequest);
- var bytesReceived = socksSocket.Receive(httpResponseBuffer,
- 0,
- httpResponseBuffer.Length,
- SocketFlags.None);
- using (var sr = new StringReader(Encoding.ASCII.GetString(httpResponseBuffer, 0, bytesReceived)))
- {
- var firstLine = sr.ReadLine();
-
- Assert.AreEqual(searchText, firstLine);
- }
+ var httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII);
+ Assert.IsTrue(httpResponse.Contains(searchText), httpResponse);
}
Assert.IsTrue(socksSocket.Connected);
// check if client socket was properly closed
- Assert.AreEqual(0, socksSocket.Receive(httpResponseBuffer, 0, httpResponseBuffer.Length, SocketFlags.None));
+ Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None));
}
[TestMethod]
public void Ssh_DynamicPortForwarding_DomainName()
{
const string searchText = "HTTP/1.1 301 Moved Permanently";
- const string hostName = "www.amazon.com";
+ const string hostName = "github.com";
// Set-up a host alias for google.be on the remote server that is not known locally; this allows us to
// verify whether the host name is resolved remotely.
const string hostNameAlias = "dynamicportforwarding-test.for.sshnet";
// Construct a HTTP request for which we expected the response to contain the search text.
- var httpGetRequest = Encoding.ASCII.GetBytes($"GET /null HTTP/1.1\r\nHost: {hostName}\r\n\r\n");
- var httpResponseBuffer = new byte[2048];
+ var httpGetRequest = Encoding.ASCII.GetBytes($"GET / HTTP/1.1\r\nHost: {hostName}\r\n\r\n");
var ipAddresses = Dns.GetHostAddresses(hostName);
var hostsFileUpdated = AddOrUpdateHostsEntry(_adminConnectionInfoFactory, ipAddresses[0], hostNameAlias);
@@ -317,18 +393,20 @@ public void Ssh_DynamicPortForwarding_DomainName()
var socksSocket = socksClient.Connect(hostNameAlias, 80);
socksSocket.Send(httpGetRequest);
- Assert.IsTrue(SocketResponseContains(socksSocket, httpResponseBuffer, searchText));
+ var httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII);
+ Assert.IsTrue(httpResponse.Contains(searchText), httpResponse);
// Verify if port is still open
socksSocket.Send(httpGetRequest);
- Assert.IsTrue(SocketResponseContains(socksSocket, httpResponseBuffer, searchText));
+ httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII);
+ Assert.IsTrue(httpResponse.Contains(searchText), httpResponse);
forwardedPort.Stop();
Assert.IsTrue(socksSocket.Connected);
// check if client socket was properly closed
- Assert.AreEqual(0, socksSocket.Receive(httpResponseBuffer, 0, httpResponseBuffer.Length, SocketFlags.None));
+ Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None));
forwardedPort.Start();
@@ -336,14 +414,15 @@ public void Ssh_DynamicPortForwarding_DomainName()
socksSocket = socksClient.Connect(hostNameAlias, 80);
socksSocket.Send(httpGetRequest);
- Assert.IsTrue(SocketResponseContains(socksSocket, httpResponseBuffer, searchText));
+ httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII);
+ Assert.IsTrue(httpResponse.Contains(searchText), httpResponse);
forwardedPort.Dispose();
Assert.IsTrue(socksSocket.Connected);
// check if client socket was properly closed
- Assert.AreEqual(0, socksSocket.Receive(httpResponseBuffer, 0, httpResponseBuffer.Length, SocketFlags.None));
+ Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None));
forwardedPort.Dispose();
}
@@ -361,7 +440,7 @@ public void Ssh_DynamicPortForwarding_DomainName()
public void Ssh_DynamicPortForwarding_IPv4()
{
const string searchText = "HTTP/1.1 301 Moved Permanently";
- const string hostName = "www.amazon.com";
+ const string hostName = "github.com";
var httpGetRequest = Encoding.ASCII.GetBytes($"GET /null HTTP/1.1\r\nHost: {hostName}\r\n\r\n");
var httpResponseBuffer = new byte[2048];
@@ -385,18 +464,13 @@ public void Ssh_DynamicPortForwarding_IPv4()
var socksSocket = socksClient.Connect(new IPEndPoint(ipv4, 80));
socksSocket.Send(httpGetRequest);
-
- var bytesReceived = socksSocket.Receive(httpResponseBuffer, 0, httpResponseBuffer.Length, SocketFlags.None);
- using (var sr = new StringReader(Encoding.ASCII.GetString(httpResponseBuffer, 0, bytesReceived)))
- {
- var firstLine = sr.ReadLine();
-
- Assert.AreEqual(searchText, firstLine);
- }
+ var httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII);
+ Assert.IsTrue(httpResponse.Contains(searchText), httpResponse);
forwardedPort.Dispose();
- Assert.AreEqual(0, socksSocket.Receive(httpResponseBuffer, 0, httpResponseBuffer.Length, SocketFlags.None));
+ // check if client socket was properly closed
+ Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None));
}
}
@@ -407,7 +481,7 @@ public void Ssh_DynamicPortForwarding_IPv4()
public void Ssh_LocalPortForwardingCloseChannels()
{
const string hostNameAlias = "localportforwarding-test.for.sshnet";
- const string hostName = "www.amazon.com";
+ const string hostName = "github.com";
var ipAddress = Dns.GetHostAddresses(hostName)[0];
@@ -435,7 +509,7 @@ public void Ssh_LocalPortForwardingCloseChannels()
try
{
- var httpRequest = (HttpWebRequest) WebRequest.Create("http://" + localEndPoint + "/null");
+ var httpRequest = (HttpWebRequest) WebRequest.Create("http://" + localEndPoint);
httpRequest.Host = hostName;
httpRequest.Method = "GET";
httpRequest.AllowAutoRedirect = false;
@@ -458,34 +532,6 @@ public void Ssh_LocalPortForwardingCloseChannels()
Assert.AreEqual(HttpStatusCode.MovedPermanently, httpResponse.StatusCode);
}
}
-
-
- /*
- if (!httpResponse.ContentType.StartsWith("text/html"))
- {
- Console.WriteLine(@"Expected 'text/html' and optionally the character, but was '{0}'.",
- httpResponse.ContentType);
- return false;
- }
-
- var responseStream = httpResponse.GetResponseStream();
- if (responseStream == null)
- {
- Console.WriteLine(@"ResponseStream is null.");
- return false;
- }
-
- using (var sr = new StreamReader(responseStream))
- {
- var responseText = sr.ReadToEnd();
- if (!responseText.Contains("301 Moved Permanently"))
- {
- Console.WriteLine(
- $@"Response does not contain 'The document has moved': {responseText}");
- return false;
- }
- }
- */
}
finally
{
@@ -507,7 +553,7 @@ public void Ssh_LocalPortForwardingCloseChannels()
public void Ssh_LocalPortForwarding()
{
const string hostNameAlias = "localportforwarding-test.for.sshnet";
- const string hostName = "www.amazon.com";
+ const string hostName = "github.com";
var ipAddress = Dns.GetHostAddresses(hostName)[0];
@@ -532,7 +578,7 @@ public void Ssh_LocalPortForwarding()
try
{
- var httpRequest = (HttpWebRequest) WebRequest.Create("http://" + localEndPoint + "/null");
+ var httpRequest = (HttpWebRequest) WebRequest.Create("http://" + localEndPoint);
httpRequest.Host = hostName;
httpRequest.Method = "GET";
httpRequest.Accept = "text/html";
@@ -556,33 +602,6 @@ public void Ssh_LocalPortForwarding()
Assert.AreEqual(HttpStatusCode.MovedPermanently, httpResponse.StatusCode);
}
}
-
- /*
- if (!httpResponse.ContentType.StartsWith("text/html"))
- {
- Console.WriteLine(@"Expected 'text/html' and optionally the character, but was '{0}'.",
- httpResponse.ContentType);
- return false;
- }
-
- var responseStream = httpResponse.GetResponseStream();
- if (responseStream == null)
- {
- Console.WriteLine(@"ResponseStream is null.");
- return false;
- }
-
- using (var sr = new StreamReader(responseStream))
- {
- var responseText = sr.ReadToEnd();
- if (!responseText.Contains("301 Moved Permanently"))
- {
- Console.WriteLine(
- $@"Response does not contain 'The document has moved': {responseText}");
- return false;
- }
- }
- */
}
finally
{
@@ -642,7 +661,7 @@ public void Ssh_RemotePortForwarding()
using (var s = client.CreateShellStream("a", 80, 25, 800, 600, 200))
{
s.WriteLine($"telnet {forwardedPort1.BoundHost} {forwardedPort1.BoundPort}");
- s.Expect("Escape character is '^]'.");
+ s.Expect($"Connected to {forwardedPort1.BoundHost}\r\n");
s.WriteLine("ABC");
s.Flush();
s.Expect("ABC");
@@ -652,7 +671,7 @@ public void Ssh_RemotePortForwarding()
using (var s = client.CreateShellStream("b", 80, 25, 800, 600, 200))
{
s.WriteLine($"telnet {forwardedPort2.BoundHost} {forwardedPort2.BoundPort}");
- s.Expect("Escape character is '^]'.");
+ s.Expect($"Connected to {forwardedPort2.BoundHost}\r\n");
s.WriteLine("DEF");
s.Flush();
s.Expect("DEF");
@@ -674,7 +693,7 @@ public void Ssh_RemotePortForwarding()
/// Issue 1591
///
[TestMethod]
- public void Ssh_ExecuteBashScript()
+ public void Ssh_ExecuteShellScript()
{
const string remoteFile = "/home/sshnet/run.sh";
const string content = "#\bin\bash\necho Hello World!";
@@ -711,7 +730,7 @@ public void Ssh_ExecuteBashScript()
var runLs = client.RunCommand("ls " + remoteFile);
var asyncResultLs = runLs.BeginExecute();
- var runScript = client.RunCommand("bash " + remoteFile);
+ var runScript = client.RunCommand(remoteFile);
var asyncResultScript = runScript.BeginExecute();
Assert.IsTrue(asyncResultScript.AsyncWaitHandle.WaitOne(10000));
@@ -906,26 +925,31 @@ private static bool RemoveHostsEntry(IConnectionInfoFactory linuxAdminConnection
}
}
- private static bool SocketResponseContains(Socket socket, byte[] httpResponseBuffer, string searchText)
+ private static string GetHttpResponse(Socket socket, Encoding encoding)
{
+ var httpResponseBuffer = new byte[2048];
+
// We expect:
// * The response to contain the searchText in the first receive.
// * The full response to be returned in the first receive.
var bytesReceived = socket.Receive(httpResponseBuffer,
- 0,
- httpResponseBuffer.Length,
- SocketFlags.None);
+ 0,
+ httpResponseBuffer.Length,
+ SocketFlags.None);
if (bytesReceived == 0)
{
- return false;
+ return null;
}
- using (var sr = new StringReader(Encoding.ASCII.GetString(httpResponseBuffer, 0, bytesReceived)))
+ if (bytesReceived == httpResponseBuffer.Length)
{
- var content = sr.ReadToEnd();
+ throw new Exception("We expect the HTTP response to be less than the buffer size. If not, we won't consume the full response.");
+ }
- return content.Contains(searchText);
+ using (var sr = new StringReader(encoding.GetString(httpResponseBuffer, 0, bytesReceived)))
+ {
+ return sr.ReadToEnd();
}
}