Archived Forum Post

Index of archived forum posts

Question:

C# SSH tunnel to Cisco device through Linux jump

Mar 14 '17 at 19:04

Hi, I am really banging my head on this problem. I would like to make app for automation of many network devices in our network. I decided for Chilkat SSH. We must connect to our network devices through JUMP linux server. Please Help - In my trying I was able to reach cisco device once but I dont know how. Also I would like to have the output of the command.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;

namespace ConsoleApplication1 {

class Program
{
    static void Main(string[] args)
    {
        //  Important: It is helpful to send the contents of the
        //  ssh.LastErrorText property when requesting support.

        Chilkat.Ssh ssh1 = new Chilkat.Ssh();

        //  Any string automatically begins a fully-functional 30-day trial.
        bool success = ssh1.UnlockComponent("Anything for 30-day trial");
        if (success != true)
        {
            Console.WriteLine(ssh1.LastErrorText);
            return;
        }

        //  Hostname may be an IP address or domain name:
        string hostname = "192.168.29.3";
        int port = 22;

        **/*INITIATE FIRST SSH CONNECTION*/**
        success = ssh1.Connect(hostname, port);
        if (success != true)
        {
            Console.WriteLine(ssh1.LastErrorText);
            return;
        }

        ssh1.IdleTimeoutMs = 15000;

        success = ssh1.AuthenticatePw("root", "neviem");
        if (success != true)
        {
            Console.WriteLine(ssh1.LastErrorText);
            return;
        }

        **/*INITIATE SECOND SSH CONNECTION*/**
        Chilkat.Ssh ssh2 = new Chilkat.Ssh();
        success = ssh2.ConnectThroughSsh(ssh1, "192.168.29.2", 22);
        if (success != true)
        {
            Console.WriteLine(ssh2.LastErrorText);
            return;
        }

        ssh2.IdleTimeoutMs = 15000;

        success = ssh2.AuthenticatePw("root", "cisco");
        if (success != true)
        {
            Console.WriteLine(ssh2.LastErrorText);
            return;
        }

        int channelNum = ssh2.OpenSessionChannel();
        if (channelNum < 0)
        {
            Console.WriteLine(ssh2.LastErrorText);
            return;
        }

        ***/*THIS IS THE SET OF COMMANDS I WANT TO RUN */***
        success = ssh2.ChannelSendString(channelNum, "ena\nshow version\n", "ansi");
        if (success != true)
        {
            Console.WriteLine(ssh2.LastErrorText);
            return;
        }
        var cmdOutput = ssh2.GetReceivedText(channelNum, "ansi");
        Console.WriteLine(cmdOutput);
        Console.ReadKey();

        ssh2.Disconnect();
        ssh1.Disconnect();
    }

} }

Accepted Answer

Thanks!

I would first try using a bare-LF line-ending, because that's normal for a Linux type system. (If the SSH server is on a Windows system, then you might need "\r\n"). So just do "ena\n". You would never do "\n\r", but only sometimes "\r\n". On a Linux system, the "\r" in the "\r\n" might be considered a char in the command and you might get some sort of "unrecognized command" error. (If you've ever saved a .sh shell script on Windows with "\r\n" line-endings and the copied to a Linux box and tried to run it, you'll know what I mean..)


Answer

What version of .NET are you using? I'll send you a pre-release of v9.5.0.66 to test.

In any case, there is one misconception in the above code. You're thinking that GetReceivedText is reading from the SSH server. It's not. You should instead call one of the ChannelRead or ChannelReceive methods to read from the channel. If successful, the received data is then "picked up" by calling GetReceivedText.

Also, sometimes the line-endings used in the command make a difference. If a bare-LF line ending doesn't trigger the execution of the command, then try CRLF ("\r\n"). This behavior is server dependent.


Answer

Make sure to read the documentation more closely...

ChannelRead returns an integer value, NOT a string.

Like I just said, you first ChannelRead/ChannelReceive, then if successful, get what was received via GetReceivedText..


Answer

UPDATE - error message provided

UnlockPrefix: Anything for 30-day trial
Architecture: Little Endian; 32-bit
Language: .NET 4.5
VerboseLogging: 0
channelNum: 101
channelRead:
  Received DISCONNECT message
  DisconnectReason: Out of context message type 94
  sshCloseChannel:
    closeChannel:
      channelSendClose:
        Sent SSH Channel CLOSE
      --channelSendClose
    --closeChannel
  --sshCloseChannel
  Received SSH disconnect!
  disconnectCode: 2
  disconnectReason: Out of context message type 94
--channelRead
retval: -1

--ChannelRead --ChilkatLog


Answer

Try this new build: http://chilkatdownload.com/prerelease/chilkatdotnet45-9.5.0-win32.zip


Answer

Also, after opening the channel, you need to start a shell session. This optionally (usually) involves calling SendReqPty with "dumb" as the value for the terminal type, and then call SendReqShell to start a shell on the channel. Then you can send commands to the shell. The "Out of context message type 94" means you were trying to send CHANNEL_DATA, which is SSH message type 94 (i.e your command) before there was a shell session.


Answer

YEEEEEEEEES !!! I really love you :D,

Finally after few days I am able to connect to Jump server (Debian) and then to Cisco Router and do what I want to do.

This command works & sends commands to Cisco IOS

ssh2.ChannelSendString(channelNum, "ena\rcisco\rshow version\r", "ansi");

Btw, Last thing I needed to change is ssh2.ChannelRead. This was not functioning (maybe it requires time-out between single commands).

So I changed that to ChannelReadAndPoll and it works like charm:

var cmdOutput = ssh2.ChannelReadAndPoll(channelNum, 200);