Key Exchange for SSH Tunnel

May 1, 2012 at 10:08 PM
Edited May 1, 2012 at 10:28 PM

Hey All,

Been trying to use the Shell functionality of SSH.NET to tunnel through multiple hosts.

Currently it appears that one is unable to tunnel from within the pseudo-shell, as key exchange does not happen for a tunnel.

Ex (pseudo-code):

[ Visual Basic ]

' Master Host server
Dim ssh_address1 as String = "address1.net" 
' This server can only be accessed from within Address1 host (tunnel)
Dim ssh_address2 as String = "address2.net" 

Dim Current_User as String = My.User.Name
Dim KeyPath as String = "C:\openssh\key"
Dim TempPassword as String = "password"
Dim SSH_Connection_Info = New PrivateKeyConnectionInfo(ssh_address1, CurrentUser, New PrivateKeyFile(File.OpenRead(KeyPath), TempPassword))

Dim SSH_Client = New SshClient(SSH_Connection_Info)

SSH_Connection_Info.Timeout = TimeSpan.FromSeconds(60)
SSH_Connection_Info.RetryAttemps = 3

SSH_Client.Connect()

	If SSH_Client.IsConnected = False Then
		MessageBox.Show("Passphrase not valid or Connection Failed")
		Exit Sub
	End If
	
Dim SSH_Shell_Stream = SSH_Client.CreateShellStream("xterm", 80, 24, 800, 600, 1024)
Dim SSH_reader = New StreamReader(SSH_Shell_Stream)
Dim SSH_writer = New StreamWriter(SSH_Shell_Stream)
SSH_writer.AutoFlush = True	

' Attempt to tunnel to second site through first Master site
SSHStreamClient.WriteLine("ssh address2.net") 

' Expect response from server
' Expect just sits there
SSHStreamClient.Expect("*** address1.net ***")


[ C# ]

// Master Host server
string ssh_address1 = "address1.net";
// This server can only be accessed from within Address1 host (tunnel)
string ssh_address2 = "address2.net";

string Current_User = My.User.Name;
string KeyPath = "C:\\openssh\\key";
string TempPassword = "password";
dynamic SSH_Connection_Info = new PrivateKeyConnectionInfo(ssh_address1, CurrentUser, new PrivateKeyFile(File.OpenRead(KeyPath), TempPassword));

dynamic SSH_Client = new SshClient(SSH_Connection_Info);

SSH_Connection_Info.Timeout = TimeSpan.FromSeconds(60);
SSH_Connection_Info.RetryAttemps = 3;

SSH_Client.Connect();

if (SSH_Client.IsConnected == false) {
	MessageBox.Show("Passphrase not valid or Connection Failed");
	return;
}

dynamic SSH_Shell_Stream = SSH_Client.CreateShellStream("xterm", 80, 24, 800, 600, 1024);
dynamic SSH_reader = new StreamReader(SSH_Shell_Stream);
dynamic SSH_writer = new StreamWriter(SSH_Shell_Stream);
SSH_writer.AutoFlush = true;

// Attempt to tunnel to second site through first Master site
SSHStreamClient.WriteLine("ssh address2.net");

// Expect response from server
// Expect just sits there
SSHStreamClient.Expect("*** address1.net ***");

 

Any help would be greatly appreciated as this will allow several projects to progress.

Also, I don't think Expect is functioning 100%... unless I am doing something wrong.

If so, please correct me, or any of the code for that matter.   :)

As always thanks to Oleg for providing an amazing library!!!

-DoW 

----------
UPDATE:

Found this thread on superuser, tried the ssh syntax to no avail.
But it is referencing exactly the behavior for which I am looking.
http://superuser.com/questions/96489/ssh-tunnel-via-multiple-hops 

May 2, 2012 at 8:50 AM
Edited May 2, 2012 at 8:51 AM

 

HI,

 

I dont call ssh on my remote server like you are trying, but I have found that I need to "expect" the command i just wrote to the stream before I "expect" the response.

maybe you can try something similar?

Is anything at all being returned on the stream?

 

Note that I use WriteLine and ReadLine directly on the ShellStream variable....

 

 

' Connect and create the shell

            connectionInfo = New PasswordConnectionInfo(hostIP, hostPort, userName, userPassword)
            connectionInfo.Timeout = TimeSpan.FromSeconds(60)
            connectionInfo.RetryAttempts = 3
            clientSSH = New SshClient(connectionInfo)



            clientSSH.Connect()


            ' Create the shell Stream now so we have it available later
            sshShellStream = clientSSH.CreateShellStream(shellName, 80, 24, 800, 600, 10000000)




..
..
..
..
	'run a command in the shell
            sshShellStream.WriteLine("export PS1=""" + shellPrompt + """")

            returnText = returnText + sshShellStream.Expect("export PS1=""" + shellPrompt + """") ' Expect the prompt command
            returnText = returnText + sshShellStream.Expect(shellPrompt) ' now expect the new prompt

 

might help!

cheers,

Paul

 

May 2, 2012 at 7:59 PM
Edited May 3, 2012 at 2:20 AM

Awesome, thanks Paul. Will try it out.

Would you happen to know anything regarding the tunneling issue?

 

--- 

UPDATE 1:

Wow, expect works like a charm now! Thanks for that tip Paul!

 

However no progress on the tunneling front.
Tried the following to no avail as a sent command:
"ssh -A -L 2222:address2:22 address1"

Is there any tunnel support in SSH.NET?
What initial setup commands does it support also (Ex: how would I add the -A ssh flag to the initial host address) ?

 

---

UPDATE 2:

Does anyone know the equivalent to the below C# in VB?

 

var port = client.AddForwardedPort<ForwardedPortRemote>(8082, "host to be forwarded", 80);

 

The converter gives me:

 

Dim port = client.AddForwardedPort(Of ForwardedPortRemote)(8082, "host to be forwarded", 80)

 

Which does not work...

 

 

--- 

UPDATE 3:

So have the following now:

If DeployClient.IsConnected Then
	Try
		Dim fPort_1 As New ForwardedPortRemote("localhost", 3333, "tunnel_address", 33)
		DeployClient.AddForwardedPort(fPort_1)
		fPort_1.Start()
	Catch ex As Exception
		MessageBox.Show(ex.ToString(), "SSH Exception", MessageBoxButtons.OK, MessageBoxIcon.Error)
	End Try
End If

Can someone explain two things to me?

1. Should I be using ForwardedPortRemote or ForwardedPortDynamic to perform the below scenario:

Initial SSH Connection to HostAddress 1 - Master (New SshClient) ---> [tunnel] to HostAddress 2 ---> Exec CMD

2. How would I then apply the below to one of the above? (normal SSH command in Putty)

ssh -A -L 2222:address2:22 address1

   Current Host Port? ^                    ^ Target Host Port?

 

Thanks to anyone for any help, much appreciated!!

May 3, 2012 at 10:54 AM

HI DoW.

glad the tip helped!

 

I'm not sure about the ssh thing you are trying to do, but if I understand correctly, you are trying to pass the authentication info from your inital ssh connection to host1, via the sshshell, into your ssh command to get to host2?

I don't know much about ssh or ssh.net, but I reckon this is not really gonna work coz the connection to host1 is created by sshclient and you then use ssh shell to try connect to host 2.... Since sshshell does not know anything about the authentication of client to host 1 (it just uses the already established connection), I don't see why it would know the authentication stuff... hence your problem...

 

Perhaps to get around it, you might be able to scp/sftp the privatekeyfile to host 1 after you connect, then establish a your ssh connection to host 2 using the privatekeyfile. Then when you disconnect from host 2, delete the privatekeyfile from host 1.

 

it's a bit of a round about way to do it but it might work...

 

cheers,

 

Paul

 

 

May 3, 2012 at 9:58 PM

So it appears the problem lies with offering the privatekey instead of the publickey during the tunnel.

Output from VB:

debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Trying private key: /home/user.name/.ssh/identity
debug1: Trying private key: /home/user.name/.ssh/id_rsa
debug1: Trying private key: /home/user.name/.ssh/id_dsa
debug1: No more authentication methods to try.
Permission denied (publickey).

However the correct output should be (from putty):

debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: rsa-key-20120125
debug1: Server accepts key: pkalg ssh-rsa blen 149
debug1: Authentication succeeded (publickey).

Any ideas???

May 9, 2012 at 1:28 AM

Can anyone comment on this....?