SshConnectionException from SshNet in C# - c#

From my script trying to connect to the unix server to download a file but getting below error..
Renci.SshNet.Common.SshConnectionException : Client not connected.
I can connect properly to that server from WinScp by using the same credentials.
Not sure what's going wrong here. Any idea/pointer ?
Code
using (var client = new ScpClient(Config.UnixServer, Config.UnixUsername, Config.UnixPassword))
{
client.Connect();
client.Upload(new FileInfo(fileUpload), fileName);
client.Disconnect();
}
Error
Renci.SshNet.Common.SshConnectionException : Client not connected.
at Renci.SshNet.Session.WaitOnHandle(WaitHandle waitHandle)
at Renci.SshNet.Session.Connect()
at Renci.SshNet.BaseClient.Connect()
WinSCP Session Log

The session log shows that WinSCP is using the sftp protocol (WinSCP supports both scp and sftp protocols). Not all sftp servers will accept scp connections. Switch to the SftpClient class and use the UploadFile method.
I also suspect you meant to call OpenRead() on your FileInfo instance to get a stream.
using (var client = new SftpClient(Config.UnixServer, Config.UnixUsername, Config.UnixPassword))
{
client.Connect();
client.UploadFile(new FileInfo(fileUpload).OpenRead(), fileName);
client.Disconnect();
}

Maybe that helps?
Maybe something to do with unix paths? Check client.RemotePathTransformation = RemotePathTransformation.ShellQuote;
Have quick read here
By default, SSH.NET applies a simple quoting mechanism for remote
paths in ScpClient. More precisely, any remote path is enclosed in
double quotes before it is passed to the scp command on the remote
host.

Perhaps the trust isn't there? In the original logs, OP has this:
2017-09-14 09:10:17.495 Host key matches cached key.
The github page: https://github.com/sshnet/SSH.NET
has information about how to establish an expected fingerprint.
The other issue I run into is when a server has a white list of IP addresses and the server is on it, but my test environment is not.
#Lee, the log from the application performing the connection is most helpful in figuring out these kinds of things, as Martin has pointed out.

Update the Renci reference lib will solved the issues.

Related

WinSCP .NET library FTP transfer fails with "IP addresses of control and data connection do not match"

I have implemented FTP code with use of WinSCP .NET assembly and hosted it on an Azure AppService.
It works locally and on Azure.
But in very few random times, when hosted on Azure, it throws the following error:
Error transferring file 'D:\local\Temp\test_settings.txt'. Server sent passive reply with unroutable address 10.YYY.YYY.YYY, using host address instead. Copying files to remote side failed. Rejected data connection for transfer of "/test_settings.txt", IP addresses of control and data connection do not match
Since the IP starts with 10. does that mean that it's local in the FTP server's network?
Can I do something to improve the implementation?
Do you think that the solution will have a problem when used concurrently by multiple requests?
My code is a copy of the Simple C# example with the following settings:
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
UserName = username,
Password = password,
GiveUpSecurityAndAcceptAnyTlsHostCertificate = true,
FtpSecure = FtpSecure.Explicit,
HostName = 'ftp.domain.com'
};
IP addresses of control and data connection do not match
That's a message from FileZilla FTP server. It's a security measure. It might indicate that external IP address of your app service instance changed mid transfer. Or of course, it might indicate that you connection was hijacked (that's what the server tries to detect).
It has nothing to do with WinSCP.
I do not know if the IP address of the Azure app service can be fixed somehow. If not, all you can do is to reconnect and retry the transfer. I believe you would have the same problem with any FTP client. Maybe with IPv6 connection, the problem would not happen. But I'm not sure, it's just a wild guess. Though you cannot force IPv6 with WinSCP (only by disabling IPv4 altogether, but I do not know if that's even possible with the app service).

SSH.NET timeout when connecting to AWS Managed SFTP server in C#

I'm having issues trying to establish a connection to an AWS Managed SFTP server. Using the credentials I have on hand, I'm able to connect to the server from my Windows command line using the sftp command. Here's my .NET code:
using (var client = new SshClient(new ConnectionInfo(baseHost, user,
new AuthenticationMethod[]{
new PrivateKeyAuthenticationMethod(user,new PrivateKeyFile[]{
new PrivateKeyFile(keyLocation, pkpassword)
}),
}
)))
{
client.Connect(); // Timeout here
}
The code above gets to the client.Connect() line, then times out after 30 seconds with a Renci.SshNet.Common.SshOperationTimeoutException exception. When I look at what's happening with Wireshark, I see that the protocol being used by the sftp command line utility is SSH, while the SSH.NET is using TCP, and the packet sizes are completely different.
Does anybody know what I might be missing here?
I'm running the sftp command-line utility on the same computer as the above code. The first Wireshark image below is from the C# code above. The second is from the sFTP utility:
When I attempt to connect to the server's port 22 using PuTTY in raw mode, I get no response.
Thanks, Jim
This is bug both in old versions of SSH.NET and on Amazon Managed SFTP server side.
According to RFC 4253 Section 4.2. Protocol Version Exchange:
When the connection has been established, both sides MUST send an identification string.
Both SSH.NET client and Amazon Managed SFTP server fail this requirement. Both first wait for the other side to send the identification string before sending its own. A deadlock is inevitable (interrupted only by a timeout). That also explains why Wireshark does not identify the session as SSH, as there's no data exchanged at all. Hence, there's nothing by which the protocol can be identified.
If you can modify SSH.NET source code, moving this line in Session.Connect:
SocketAbstraction.Send(_socket, Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0}\x0D\x0A", ClientVersion)));
... above this block:
Match versionMatch;
// Get server version from the server,
// ignore text lines which are sent before if any
while (true)
{
...
}
... should fix the problem.
Also consider reporting the bug to Amazon.
I have reported the bug to SSH.NET
including the needed change. The fix is included from SSH.NET 2020.0.0 up.
If you cannot change SSH.NET code, you will need to use another SFTP library.
For example my WinSCP .NET assembly is compatible with Amazon Managed SFTP server.
This is an equivalent of your code:
// Set up session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = baseHost,
UserName = user,
SshHostKeyFingerprint = ...,
SshPrivateKeyPath = keyLocation,
PrivateKeyPassphrase = pkpassword,
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Your code
}
WinSCP GUI can generate a code template like the one above for you.

How to perform "double hop" via SFTP/SSH in .NET?

In my scenario i am trying to go from Local App Server -> Middle Server (DMZ) -> Client Server
I need to move files from the Local App Server to the Client Server and back.
So my question is what is the most widely used standard for doing this?
I am currently using WinSCP to connect to the Middle Server via SFTP, and then invoking a command on the Middle Server to download and upload files to the Client Server. I'm not really a fan of this, as i feel like its prone to error as i am manually entering a command, rather than using the WinSCP's library to upload and download. It also leaves me stuck when i try to list all files on the Client Server with a command, as the function returns void
I have looked at SSH.NET which seems like its more widely used, however i cant see any real way of performing a "double hop" with that library either.
With WinSCP .NET assembly, it's easy:
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = "example.com",
UserName = "username",
Password = "password",
SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...=",
};
sessionOptions.AddRawSettings("Tunnel", "on");
sessionOptions.AddRawSettings("TunnelHostName", "tunnel.example.com");
sessionOptions.AddRawSettings("TunnelUserName", "username");
sessionOptions.AddRawSettings("TunnelPasswordPlain", "password");
sessionOptions.AddRawSettings("TunnelHostKey", "ssh-rsa 2048 xxxxxxxxxxx...=");
using (Session session = new Session())
{
session.Open(sessionOptions);
// Your code
}
WinSCP GUI can generate a code template to connect through tunnel, like the one above, for you (except for the TunnelHostKey).
With SSH.NET you can implement a port forwarding explicitly by:
opening connection to the "Middle Server";
creating a forwarded port;
opening a second connection to the forwarded port.
For some example, see Connection to MySQL from .NET using SSH.NET Library.
Another hackish solution is to execute ssh on the "Middle Server" to facilitate the second "hop".

SSH.NET - Message type 80 is not valid

I have the following piece of code that tries to connect to an SFTP Server built with OpenSSH (The server works because I've been able to successfully connect to this FTP via WinSCP client):
ConnectionInfo ConnNfo = new ConnectionInfo("127.0.0.1", 22, "usertest",
new AuthenticationMethod[]{
// Pasword based Authentication
new PasswordAuthenticationMethod("usertest","usertest"),
}
);
// Upload A File
using (var sftp = new SftpClient(ConnNfo))
{
sftp.Connect();
sftp.ChangeDirectory(#"/C:/IISFTP/");
using (var uplfileStream = File.OpenRead(uploadfn))
{
sftp.UploadFile(uplfileStream, uploadfn, true);
}
sftp.Disconnect();
}
When calling the sftp.Connect() line, it raises the following Exception:
Message type 80 is not valid
Why is this happening? How can I connect to my SFTP server with SSH.NET?
Thank you
The message 80 stands for SSH_MSG_GLOBAL_REQUEST.
Modern versions of OpenSSH server use this generic message for various proprietary extensions of the SSH protocol.
Most clients will/should silently ignore unrecognized messages. The SSH.NET does ignore the SSH_MSG_GLOBAL_REQUEST too, but it does not expect the message until an authentication completes.
Unfortunately it seems that OpenSSH sends some of these (maybe the hostkeys-prove-00#openssh.com) even before the authentication.
The problem has been fixed in SSH.NET 2016.0.0-beta1. See Issue #8 and Commit a1f46d4.
In older versions, go to the Session.cs and in the Session.Connect() method move the below line somewhat up, above the authentication code:
RegisterMessage("SSH_MSG_GLOBAL_REQUEST");
I'd put it, just below this line:
RegisterMessage("SSH_MSG_USERAUTH_BANNER");

Problem with deleting a file over FTP

I am using C# to upload some file to a ftp server. If the file already existed the FtpWebRequest timed out, so I thought to deleate it first.
However the WebRequestMethods.Ftp.DeleteFile also always times out. Am I doing something wrong?
Here is my code:
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(address);
request.Credentials = new NetworkCredential(Username, Password);
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.DeleteFile;
try
{
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
}
catch (Exception e)
{
...
}
EDIT: Oh and it doesn't matter witch file I am trying to delete. As long as the file exists the request will always time out. If the file doesn't exist a different exception is thrown.
Nothing is wrong with credentials, I can do other operations (upload/download without a problem). Also it's not a server problem, if I connect to it with a client (FileZilla) with the same username / pass everything works as it should.
Thank you for your help.
The thing I have found using this Ftp via FtpWebRequest, is it is inherently a lot slower (since it is using the HTTP protocol over port 80), and it drives me crazy because FileZilla can do it a lot quicker (obviously using FTP protocol over port 20/21). There is a open source ftp component found here, I do not know if it will work for you, but worth a shot.
I know this is a subjective answer that will get downvoted, but personally, using ftp over port 80 is bound to be a lot slower especially on file operations like what you are trying to achieve.
Do you have access to the logs of the FTP server? If you do have a look at what commands the FTPWebRequest is making. It could be that it is trying to list the directory before deleting it.
Another issue maybe that the server is in passive mode, I believe FileZilla may automagicly detect this, check the connection in filezilla to see.
Knowing what commands are sent between client and FTP server could help find out what is causing the timeout. Would it be possible to use a packet analyzer such as Ethereal to capture the communication log?
Alternative approach could be using a third party FTP component and enabling logging in it. Following code uses our Rebex FTP:
// create client
Ftp client = new Ftp();
// enable logging
client.LogWriter = new Rebex.FileLogWriter(#"c:\temp\log.txt", Rebex.LogLevel.Debug);
// connect
client.Connect("ftp.example.org");
client.Login("username", "password");
// browse directories, transfer files
client.DeleteFile("file.txt");
// disconnect
client.Disconnect();

Categories