Hello,
I would like to connect from Windows XP to SSH2 server and from there establish a telnet
connection to device. I would like to send a command to this device, wait expected
prompt from the telnet session over SSH connection and read the result. So far best
results have been with Net::SSH2. The problem is the telnet connection.
The problem is that after I issue 'telnet <IP Address>' command, I cannot read
the data without breaking the command sending/reading. If I read the result once after
telnet has been established, I get after that only the command that was sent. For example
after sending the telnet command, I read the result to look for username prompt and send
the username. After this I get only the username that was sent as a result, not the
actual output. Seems like output and input are mixed after first read.
I can issue the commands over telnet session quite nicely if I do not read the results at
all. But unfortunately, I need to parse the output and decide following actions based on
collected data. This might be possible with several sequential sessions, but I am looking
send command, wait expected data and read response type of solution on Windows machine.
I am trying to compile this as executable with ActiveState tools and for this reason
I don't think that Cygwin is an option.
Is there a way to do this on Windows machine? Is this somehow related to terminal settings
that I should modify before establishing the telnet session? Newbie question, but I was not
able to find the module where implementation of $channel->read() really is?
Thank You
#!/usr/bin/perl
# Tested with ActiveState perl version 5.8.8 on Windows XP SP3.
use strict;
use warnings;
use Net::SSH2; # Using version 0.28.
use Data::Dumper;
#Net::SSH2->debug(1);
use constant NEWLINE => qq{\n};
my $g_ssh_server = '<10.10.10.10>'; # SSH server addresss
my $g_username = '<username>';
my $g_password = '<password>';
my $g_prompt = '<ssh server prompt>';
my $g_telnet_cmd = 'telnet <10.10.10.10>'; # Command to telnet
my $g_ssh = undef;
my $g_channel = undef;
# Connection opened with shell.
SSH2Open(\$g_ssh, \$g_channel);
# Separate commands are executed and read nicely.
SSH2Send($g_ssh, $g_channel, "\n", $g_prompt);
SSH2Send($g_ssh, $g_channel, 'ls -al', $g_prompt);
SSH2Send($g_ssh, $g_channel, 'uname -a', $g_prompt);
SSH2Send($g_ssh, $g_channel, 'ls -l', $g_prompt);
# Starting telnet causes problems if command output is read
SSH2Send($g_ssh, $g_channel, $g_telnet_cmd, '<expect username prom>');
SSH2Send($g_ssh, $g_channel, 'username', '<expect password prom>');
SSH2Send($g_ssh, $g_channel, 'passowrd', '<expect terminal prom>');
SSH2Send($g_ssh, $g_channel, 'ls -al', '<expect terminal prom>');
# Read to test commands without reading after each command.
SSH2Read($g_ssh, $g_channel);
sub SSH2Open{
my $ssh2 = shift; # OUT
my $channel = shift; # OUT
${$ssh2} = Net::SSH2->new();
${$ssh2}->connect($g_ssh_server) or die $!;
${$ssh2}->auth_password($g_username, $g_password) or die 'Auth. Fail
+ed';
${$channel} = ${$ssh2}->channel();
${$channel}->pty('vt80'); # To get the prompt also.
${$channel}->shell();
return;
}
sub SSH2Send{
my $ssh = shift; # IN
my $channel = shift; # IN - Created channel
my $command = shift; # IN - Command to be sent
my $waitfor = shift; # IN - String to be waited for.
my $found = 0;
my $string = q{};
my @result = ();
print "===============================\n";
print "send command ($command)\n";
$channel->write(($command . NEWLINE));
if(0)
{
# Read response with method 1. This works randomly depending on
# latency I quess. This may not read all of the data or last
# command reads the data for every command.
$string = q{};
while( <$channel> ) {
$string = $string . $_;
}
}
if(0)
{
# Read response with method 2. same as method 1.
$string = q{};
my @result = readline($channel);
$string = $string . join("\n", @result);
}
# Read response with method 3. Try polling until requested prompt
# found. Based on http://search.cpan.org/~remi/Net-SSH2-Simple/.
if(1)
{
my( $n, $buffer );
my @poll = ({handle => $channel, events => ['in', 'ext', 'err']});
$string = q{};
$channel->blocking(0);
while(not $channel->eof and not $found) {
$ssh->poll( 2000, [ @poll ] ); # 2 seconds
print "poll" . Dumper \@poll;
foreach my $poll ( @poll ) {
foreach my $event ( qw( in ext ) ) {
next unless $poll->{revents}{$event};
if($n = $channel->read( $buffer, 10_240, $event eq 'ext' )){
$string = $string . $buffer;
#print "read string ($n) - $string\n";
}
# Check if the requested data was read.
$found = __test_waitfor($waitfor, $string);
}
}
}
}
print "response: $string\n";
print "===============================\n";
return;
}
sub SSH2Read{
my $ssh = shift; # IN
my $channel = shift; # IN
my $string = q{};
if(0)
{
$string = q{};
while( <$channel> ) {
$string = $string . $_;
}
print "string $string\n";
}
return;
}
sub __test_waitfor{
my $waitfor = shift; # IN
my $string = shift; # IN
my $last_line = q{};
my $found = 0;
# If user defined waitfor, it is checked from last line of the
# string. Otherwise the string is just tested for couple of
# characters.
if( $waitfor ) {
($last_line) = $string =~ m/\n?(.*)\z/x;
if( $last_line ) {
print "last line ($last_line) wait ($waitfor)\n";
if( $last_line =~ m/$waitfor/ ) {
$found = 1;
}
}
}
elsif( 5 < length $string ) {
$found = 1;
}
return $found;
}