pbwiz1970 has asked for the wisdom of the Perl Monks concerning the following question:

So, here is the situation.

Once upon a time, an organization decided to switch all of its network equipment (routers, switches) from Telnet to SSH. Try as we did, we could not get the necessary modules to install on our antiquated equipment so that we could just call Net::SSH::Perl.

So, we devised a cunning plan to use Net::Telnet to telnet to a unix server that does have SSH capability. This has worked marvelously, as we no longer had to recode the entire series of scripts to use Net::SSH::Perl instead of Net::Telnet.

So now, the powers that be have declared that Telnet shall no longer be an option on these unix servers, and have given us very little notice.

So, my plan is as follows: Install Putty tools on the server (windows, btw) and somehow initiate a shell to it, run plink to run putty from the command line to ssh to that unix server, then everything else remains the same.

However, I am not sure how to accomplish this. Basically, my code looks sort of like this:

my $device = Net::Telnet->new(Timeout => 10, Errmode => 'return'); $device->open(Host => &SSH_HELPIP, Port => &SSH_HELPPORT); if(!$device) { print "Unable to connect to SSH Helper\n" if ($var->{debug}); return undef; } my ($prematch, $match) = $device->waitfor('/:/'); #print "$prematch and $match<br>\n"; if ($prematch =~ /login/) { $device->print(&SSH_ID); } else { print "Timeout waiting for login prompt on SSH Helper - $prema +tch and $match\n" if ($var->{debug}); return undef; } my ($prematch, $match) = $device->waitfor('/:/'); #print "$prematch and $match<br>\n"; if ($prematch =~ /Password/) { $device->buffer_empty(); $device->print(&SSH_PW); } else { print "Timeout waiting for password prompt on SSH Helper\n" if + ($var->{debug}); return undef; } $device->waitfor('/\$/'); $device->print('ssh -l testid ' . $ip); my ($prematch, $match) = $device->waitfor('/\?|word:/') +; if ($prematch =~ /re you sure you want to continue conn +ecting/) { $device->print("yes"); my ($newpmatch, $newmatch) = $device->waitfor('/word +:/'); if ($newpmatch =~ /pass/) { $device->print(&PWD()); } } else { if ($prematch =~ /pass/) { $device->print(&PWD()); } } return $device;

So, I am basically establishing a device handle through telnet, and using its waitfor and cmd and print capabilities to parse commands and respons appropriately.

I will eventually have to re-write the whole system to use Net::SSH::Perl, but I need a quick solution that can allow me to SSH to my helper server, and then reuse my existing code to interact and parse.

Any ideas?

Thanks!

Replies are listed 'Best First'.
Re: Making a shell work like a Net::Telnet session
by ikegami (Patriarch) on Feb 09, 2011 at 21:52 UTC

    So now, the powers that be have declared that Telnet shall no longer be an option on these unix servers

    Their concern is surely unencrypted communication over the wire. Could you convince them to still run the telnet server, but only accept connections from localhost? That addresses their concern, and opens the simple solution of creating a ssh tunnel using putty or whatever.

    +--------------------+ +--------------------+ | | | | | +--------+ | | +--------+ | | | Perl | | | | Telnet | | | | script | | | | server | | | +--------+ | | +--------+ | | | | | ^ | | v | | | | | +--------+ | | +--------+ | | | Tunnel |~~~~~~~~~~~~~~>| Tunnel | | | +--------+ | | +--------+ | | | | | +--------------------+ +--------------------+ ~ = encrypted

    Try as we did, we could not get the necessary modules to install on our antiquated equipment

    It's not clear to me which machine can and can't do what. I would also like to know their OS. (Don't need specifics; Windows vs unix should do.)

      The solution needs to run on Windows 2000 and Windows 2003 server. That server currently opens a telnet session to a solaris server that then connects to remote devices via SSH.

      So, basically, I want to capture a shell session the same way that I capture a telnet session today. Inside that session, I use plink to ssh to my solaris server, then it SSH's to the devices.

        It's unfortunate that you didn't clear up which machine can and can't do what. I'm guessing now that you were saying you couldn't get Net::SSH::Perl installed on the Windows machine.

        Instead, you made it less clear by saying the solution must run on Windows. Does that mean you want to take Solaris out of the solution?

        And you didn't comment at all on the solution I proposed.

Re: Making a shell work like a Net::Telnet session
by furry_marmot (Pilgrim) on Feb 09, 2011 at 23:57 UTC
    Take a look at Net::SFTP::Foreign. From the docs: "Net::SFTP::Foreign uses any compatible ssh command installed on the system (for instance, OpenSSH ssh) to establish the secure connection to the remote server." It specifically supports plink.

    --marmot

      Net::SFTP::Foreign does support file transfer operations only, it can not be used to run arbitrary commands on the remote hosts.
Re: Making a shell work like a Net::Telnet session
by salva (Canon) on Feb 10, 2011 at 15:46 UTC
    Net::SSH::Perl is old and unmaintained. Nowadays, on Windows, Net::SSH2 is a better option.

    Anyway, as you are connecting to network equipment that usually has custom shells, what you probably need is something for automating interactive dialogs as Expect or Net::SSH::Expect, but those modules, on Windows, only work under Cygwin Perl.

    If you can, move that application to a Unix (or Linux) machine (use a virtual machine or whatever), or break it into two parts using some kind of RPC and run the SSH part inside a Unix box. Otherwise, you will waste your time trying to overcome limitations intrinsic to Windows just to do things that on Unix are trivial.

Re: Making a shell work like a Net::Telnet session
by belden (Friar) on Feb 10, 2011 at 15:29 UTC
    I must be missing something here. It sounds like you used to have:
    script-on-box --telnet--> hardware.
    And now the hardware doesn't accept telnet connections, and you've got your script-on-box that doesn't know how to do ssh. So you want to do:
    script-on-box --telnet--> another box --ssh--> hardware
    Net::Telnet will allow you to connect to an ssh session, so you could just spawn an ssh connection to the piece of hardware, then attach that ssh connection to your Net::Telnet object. (Search for 'spawn' in the Net::Telnet perldoc for an example of this.) Your script would continue to behave as it has in the past, interacting with a Net::Telnet object that just happens to be speaking ssh.

    But I assume you already know this, so what am I missing?

      Have you actually tried the spawn sample on a Windows box? I am almost sure it will not work.

      IO::Pty does not compile there, you could just use IPC::Open2 but Net::Telnet uses select to poll the connection and on Windows select does not work with pipes.

      Later versions of perl have a socketpair emulation that uses TCP internally (it goes through localhost) but the last time I tried it with OpenSSH, it didn't like having its stdio attached to a TCP socket.

        Aha! Okay - I missed that this was on a Windows box. Thanks for the clarification.