0

I am having a slight issue. First and foremost, I had never written a single line of Ruby until being given this task so it is somewhat outwith my remit and comfort zone. This may well be a stupid question but I have searched for what feels like an eternity and found nothing.

I have found a wealth of information on how to telnet from my local machine using Net::Telnet and how to create a Telnet session based on the current SSH session using Net::SSH:Telnet but haven't found anything specifically dealing with my issue.

I need to SSH onto a machine using a set of credentials; this is no issue:

objSsh=Net::SSH.start("xxx.xxx.xxx.xx",
                        "sshUser", 
                        :Password=>"sshPass")

The above works a treat and I can get, for example, the output from ls (I know, the simplest of simpleton tasks).

The issue that I am having is that I need to Telnet from the SSH session using different credentials, so the below does not fit my purpose:

ssh = Net::SSH.start("xxx.xxx.xxx.xxx",
      :username=>"sshUser",
      :password=>"sshPass"
)
s = Net::SSH::Telnet.new(
      "Dump_log" => "/dev/stdout",
      "Session" => ssh
)

That would Telnet using the same credentials and so is not what I require.

But at the same time I cannot use the below because it would just try to Telnet from the executing machine, which is not what is required.

s = Net::SSH::Telnet.new(
    "Dump_log" => "/dev/stdout",
    "Host" => "0",
    "Username" => "telnetUser",
    "Password" => "telnetUser"
)

Basically, I need to SSH to a machine then, using different credentials, Telnet to the localhost using "telnet 0 xxxxx" but can't figure out for the life of me how to do it.

I've tried running telnet 0 xxxxx at the ssh prompt but that just hangs, presumably because the username/password prompts are shown.

I am wandering in confused circles, here. Any assistance with regards to a kick in the right direction would be appreciated.

Thanks,

CJL.

Update 1:

Thank you cherrysoft for your rapid and helpful replies. I'll look into whether or not we are able to chuck files onto their servers to trigger via SSH directly. It would make life simpler!

Update 2:

OK, so in desperation I tried something and it got me a step further than I was getting before. The following code connects via SSH, creates a Telnet session based on the SSH, ensures everything is still working by outputting a simple SSH command, tries to kick off a Telnet session....and then fails.

#Create SSH connection.
objSsh=Net::SSH.start("xxx.xxx.xxx.xxx",
                    "sshPass", 
                    :password=>"sshPass")
#Crete a Net:SSH:Telnet object based on the SSH connection.
objTelnet = Net::SSH::Telnet.new("Session" => objSsh)
#Ensure simple SSH commands can still be run by outputting ls results.
p objTelnet.cmd("ls")
#Try to kick off a telnet session and show what is displayed.
p objTelnet.cmd("telnet 0 xxxxx")
#Wait for the Username prompt.
objTelnet.waitfor("Match" => /.*?Username:.$/)
#Enter username.
objTelnet.puts("telnetUser")
#Wait for password prompt.
objTelnet.waitfor("Match" => /.*?Password:.$/)
#enter password.
objTelnet.puts("telnetPass")
#Try the command.
p objTelnet.cmd("cluster stats")

It gets as far as the Telnet connection but the Waitfor calls don't seem to be working. When the below line runs the result in the output is a prompt for Username:

objTelnet.cmd("telnet 0 xxxxx")

"telnet 0 xxxxx\nTrying 0.0.0.0...\r\nConnected to 0.\r\nEscape character is '^]'.\r\nUsername: "

I would have expected the Waitfor to match what was shown in the output and for the Username then to be entered. Is this possibly a RegEx issue? I have run it through Rubular and it seems to match but I may be missing something syntax related?

Thanks again for your time.

CJL.

UPDATE 3 AND RESOLUTION:

Thank you Kimmo Lehto. With only minor tweeking that worked perfectly. It was still getting stuck at Telnet loggin but when passing credentials as shown below (as opposed to user/pass) it works a treat!

loginInfo = {"Name" => telnetUser,
          "Password" => telnetpass,
          "LoginPrompt" => /Username:/
         }
objGateway = Net::SSH::Gateway.new(hostIp, user, :password => password)
objLocalPort = objGateway.open("localhost", port)
objTelnet = Net::Telnet::new("Host" => "127.0.0.1", "Port" => objLocalPort)
objTelnet.login(loginInfo) 
objTelnet.cmd("cluster lrm res sum") { |c| print c}
objTelnet.close
objGateway.shutdown!

Thanks again for your time and effort in resolving this issue.

CJL out...

CJL
  • 3
  • 5
  • What do you need to do in your telnet session? This might determine the best solution... – cherrysoft Jan 23 '19 at 14:26
  • Needing to run a variety of status checks (cluster stats etc). – CJL Jan 23 '19 at 14:45
  • Cool, then below should work for you. You can build up the output (if that works) or you can run multiple execs to different variables and output separately or store somewhere - start small. What I mean by this is simplest command first, get it working and then build on that. – cherrysoft Jan 23 '19 at 14:49
  • Could it be that your regexps are not matching the Username prompt? For starters, the `/.*?` in the beginning does nothing. The `/.$/` in the end may actually be waiting for "any character + linefeed". Maybe try with `/Username:/`. – Kimmo Lehto Jan 24 '19 at 07:55

2 Answers2

0

You can execute commands in SSH as follows...

Net::SSH.start('host', 'user', password: "password") do |ssh|
  output = ssh.exec!("echo {your command} | telnet {host} {port}")
  puts output
end
cherrysoft
  • 1,165
  • 8
  • 17
  • This would work fine if the credentials were the same for SSH and Telnet but I need to use a different set of credentials for the Telnet connection. The connection just gets closed because the SSH creds are invalid for Telnet. – CJL Jan 23 '19 at 14:50
  • Then why don't you create a Ruby script that performs all of your telnet operations and remotely execute that from the machine via SSH directly as opposed to using SSH in Ruby? It is not mandatory that you use Ruby for SSH. – cherrysoft Jan 23 '19 at 16:30
0

You could try using net-ssh-gateway for tunneling and use the regular net-telnet for telnet (which itself is horribly outdated and net-telnet-ssh is a drop-in replacement of that horribleness):

gateway = Net::SSH::Gateway.new(ssh_host, ssh_user)
local_port = gateway.open(target_host, target_port)
telnet = Net::Telnet::new("Host" => "localhost", "Port" => local_port)
telnet.login(telnet_user, telnet_password)
telnet.cmd("ls -al") { |c| print c }
telnet.close
gateway.shutdown!

Quick googling did not bring up any alternative telnet libraries that would look like the ruby of today.

Kimmo Lehto
  • 5,910
  • 1
  • 23
  • 32