5

I'm working with the Renci SSH.Net library on a WPF application and I'm having an issue with using the SFTP client. When the user tries to connect to download some files from the SFTP server he gets the message shown below:

Server response does not contain ssh protocol identification

It doesn't appear to be something specific with the server as I'm able to connect and download the files just fine on my development desktop and a secondary laptop. The same application is able to connect over SSH and run commands without issue, it's just the SFTP connection that appears to be the problem. I'm looking for a little guidance as to where to begin troubleshooting this.

Code for SFTP shown below:

void DownloadPlogs()
    {
        try
        {
            SftpClient SFTP;
            if (GV.UseCustomPort && GV.CustomPort > 0 && GV.CustomPort < 65535)
            {
                SFTP = new SftpClient(GV.IpAddress, GV.CustomPort, GV.Username, GV.Password);
            }
            else
            {
                SFTP = new SftpClient(GV.IpAddress, 22, GV.Username, "");
            }
            SFTP.Connect();

            DownloadDirectory(SFTP, "/PLOG", Directory.GetCurrentDirectory() + @"\PLOG");
            ZipFile.CreateFromDirectory("PLOG", String.Format("{0} - {1} PLOGS.zip", GV.IpAddress, DateTime.Now.ToString("yyyyMMddHHmmss")));
            Directory.Delete(Directory.GetCurrentDirectory() + @"\PLOG", true);

            SFTP.Disconnect();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error Getting PLOGS");
        }
    }

    void DownloadDirectory(SftpClient Client, string Source, string Destination)
    {
        var Files = Client.ListDirectory(Source);
        foreach (var File in Files)
        {
            if (!File.IsDirectory && !File.IsSymbolicLink)
            {
                DownloadFile(Client, File, Destination);
            }
            else if (File.IsSymbolicLink)
            {
                //Ignore
            }
            else if (File.Name != "." && File.Name != "..")
            {
                var Dir = Directory.CreateDirectory(System.IO.Path.Combine(Destination, File.Name));
                DownloadDirectory(Client, File.FullName, Dir.FullName);
            }
        }
    }

    void DownloadFile(SftpClient Client, Renci.SshNet.Sftp.SftpFile File, string Directory)
    {
        using (Stream FileStream = System.IO.File.OpenWrite(System.IO.Path.Combine(Directory, File.Name)))
        {
            Client.DownloadFile(File.FullName, FileStream);
        }
    }

Code for SSH below:

public SshConnection(string Host, int Port, string Username, string Password)
    {
        myClient = new SshClient(Host, Port, Username, Password);
        myClient.KeepAliveInterval = new TimeSpan(0, 0, 5);
        myClient.HostKeyReceived += myClient_HostKeyReceived;
        myClient.ErrorOccurred += myClient_ErrorOccurred;
    }

void myClient_ErrorOccurred(object sender, Renci.SshNet.Common.ExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message, "SSH Error Occurred");
    }

    void myClient_HostKeyReceived(object sender, Renci.SshNet.Common.HostKeyEventArgs e)
    {
        e.CanTrust = true;
    }

    public async void Connect()
    {
        Task T = new Task(() =>
        {
            try
            {
                myClient.Connect();
            }
            catch (System.Net.Sockets.SocketException)
            {
                MessageBox.Show("Invalid IP Address or Hostname", "SSH Connection Error");
            }
            catch (Renci.SshNet.Common.SshAuthenticationException ex)
            {
                MessageBox.Show(ex.Message, "SSH Authentication Error");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.StackTrace, ex.Message);
                MessageBox.Show(ex.GetType().ToString());
                OnConnection(this, new ConnectEventArgs(myClient.IsConnected));
            }
        });

        T.Start();
        await T;
        if (T.IsCompleted)
        {
            OnConnection(this, new ConnectEventArgs(myClient.IsConnected));
        }
    }

    public void Disconnect()
    {
        try
        {
            myClient.Disconnect();
            OnConnection(this, new ConnectEventArgs(myClient.IsConnected));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.StackTrace, ex.Message);
        }
    }

    public void SendData(string Data)
    {
        try
        {
            if (Data.EndsWith("\r\n"))
            {
                RunCommandAsync(Data, SshCommandRx);
            }
            else
            {
                RunCommandAsync(String.Format("{0}\r\n",Data), SshCommandRx);
            }
            //SshCommand Command = myClient.RunCommand(Data);
            //OnDataReceived(this, new DataEventArgs(Command.Result));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.StackTrace, ex.Message);
        }
    }

    private async void RunCommandAsync(String Data, SshCommandCallback Callback)
    {
        Task<SshCommand> T = new Task<SshCommand>(() =>
        {
            try
            {
                SshCommand Command = myClient.RunCommand(Data);
                return Command;
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().ToString());
                return null;
            }
        });

        T.Start();
        await T;
        if (T.IsCompleted)
        {
            Callback(this, T.Result);
        }
    }

    private void SshCommandRx(SshConnection C, SshCommand Command)
    {
        if (Command != null)
        {
            string Rx = Command.Result;
            //if (Rx.StartsWith(Command.CommandText))
            //{
            //    Rx = Rx.Remove(0, Command.CommandText.Length);
            //}
            while (Rx.EndsWith("\r\n\r\n") == false)
            {
                Rx += "\r\n";
            }
            OnDataReceived(this, new DataEventArgs(Rx));
        }
    }
Chris
  • 667
  • 1
  • 5
  • 16
  • wireshark. If this fails before your encrypted SSH connection is brought up, this will definitely be understandable in wireshark. – Marcus Müller Aug 26 '17 at 18:32
  • According to the renci [source code](https://github.com/darinkes/ssh.net/blob/master/Renci.SshClient/Renci.SshNet/Session.cs#L556), that error is emitted if it doesn't get a version string from the server. My guess is you're getting [this](https://stackoverflow.com/documentation/ssh/2926/debugging-ssh-problems/25955/ssh-exchange-identification-connection-closed-by-remote-host#t=201708262348300369507) or maybe [this](https://stackoverflow.com/documentation/ssh/2926/debugging-ssh-problems/25954/ssh-exchange-identification-read-connection-reset-by-peer#t=201708262348597666124). – Kenster Aug 26 '17 at 23:49
  • *"The same application is able to connect over SSH and run commands without issue, it's just the SFTP connection that appears to be the problem."* - Against the same server? Or different server for SSH and SFTP? – Martin Prikryl Aug 27 '17 at 11:02
  • @MartinPrikryl Yes, this is against the same server. I'm also able to connect on two other client machines without an issue against the same server so I'm thinking it's something client machine specific. – Chris Aug 27 '17 at 14:28
  • That is does not make any sense. Because your SFTP connection fails at a moment, where only an SSH connection is being created and no SFTP is involved yet. Show us your code, both for SSH and SFTP. – Martin Prikryl Aug 27 '17 at 14:38
  • @MartinPrikryl You're correct that it doesn't make any sense. It's quite baffling. I've updated to include the code. The only thing I noticed is that I don't register for the HostKeyReceived event for SFTP. It doesn't appear to be required however as it works fine on other machines without it. – Chris Aug 28 '17 at 15:51
  • [mcve], please! – Martin Prikryl Aug 28 '17 at 16:01
  • I apologize @MartinPrikryl. I'm new to the site and thought I provided minimal, complete, and verifiable. Was there something missing? – Chris Aug 28 '17 at 16:34
  • 1) Most of the code is irrelevant. We care about connection part only. 2) You didn't show us how you create `myClient`. 3) We need some real examples, not generic code like `new SftpClient(GV.IpAddress, GV.CustomPort, GV.Username, GV.Password);` – Martin Prikryl Aug 28 '17 at 16:40
  • Added the myClient creation. As far as the GV.IpAddress, etc, goes, that is the actual code. I merely have the WPF fields bound to a class containing that data. – Chris Aug 28 '17 at 16:52
  • And that's what makes it in-complete example. Read the article linked in my previous comment. – Martin Prikryl Aug 28 '17 at 18:19

2 Answers2

3

I solve it for my self only with connections retrying attempts. Didn't find what exactly the issue is, but have this connection issue many times.

Example:

int attempts = 0;
            do
            {
                try
                {
                    client.Connect();
                }
                catch (Renci.SshNet.Common.SshConnectionException e)
                {
                    attempts++;
                }
            } while (attempts < _connectiontRetryAttempts && !client.IsConnected);
grinay
  • 611
  • 1
  • 4
  • 17
  • If it's any other type of exception, will the do-while ever exit? – Brett Bim Mar 04 '19 at 20:42
  • Yes. If there will occur any other exception in this particular piece of code the "do while" will be interrupted. You have to take care about other exceptions as well. – grinay Mar 05 '19 at 01:08
2

I experienced the same odd error message when attempting to connect to a SFTP server while using the SSH.NET library in a program on the server. The problem did not appear while testing from my development machine.

The solution was to have our server team add the IP address of the server into the hosts.allow file on the SFTP Linux server.

ThePeter
  • 783
  • 1
  • 6
  • 13
  • 1
    I experienced a similar issue. The vendor has a white list of IPs that can connect. Coding off VPN caused this error; however, it worked fine over VPN. – David Yates Apr 27 '20 at 22:12