|
Softpanorama
(slightly skeptical)
Open Source Software Educational Society |
May the
source be with you,
but remember the KISS principle ;-)
|
Using Perl to simulate Telnet from a Program
If you are running a monitoring application it is often useful to simulate
a telnet connection from your program to a remote machine using telnet,
then issues one or a couple of commands and process output to generate alerts
or status report.
The simplest way to accomplish this is to use Expect (or
Perl
Expect.pm) but you can use the CPAN module
Net::Telnet too:
use Net::Telnet;
$t = Net::Telnet->new( Timeout => 10,
Prompt => '/%/',
Host => $hostname );
$t->login($username, $password);
@files = $t->cmd("ls");
$t->print("top");
(undef, $process_string) = $t->waitfor('/\d+ processes/');
$t->close;
Net::Telnet provides an interface to the telnet protocol. It has object-oriented flavor
(which is unnnessary in case of a single connection, but beneficial for
multiple connections)
You first need to create
a connection with Net::Telnet->new, and then interact with the remote machine
using method calls on the resulting object.
The new method requers passing several parameters in form of a hash. The most important is
Host, the machine you're telnetting to. The default host is localhost. If
you want to telnet to a port other than one telnet normally uses, specify
this in the Port option. Error handling is done through the function whose
reference is specified in the Errmode parameter.
Another important option is Prompt. When you log in or run a command,
Net::Telnet uses the Prompt pattern to determine when the login or command
has completed. The default Prompt is:
/[\$%#>] $/
which matches the common shell prompts. If the prompt on the remote machine
doesn't match the default pattern, you have to specify your own. Remember
to include the slashes.
Timeout lets you control how long (in seconds) network operations wait
before they give up. The default is 10 seconds.
If an error or timeout occurs in the
Net::Telnet module, the default
behavior is to raise an exception, which, if uncaught, prints a message
to STDERR and exits. To change this, pass a subroutine reference to new
in the Errmode argument. If instead of a code subroutine, you specify the
string "return" as the Errmode, methods return undef (in scalar context)
or an empty list (in list context) on error, with the error message available
via the errmsg method:
$telnet = Net::Telnet->new( Errmode => sub { main::log(@_) }, ... );
The login method is used to send a username and password to the remote
machine. It uses the Prompt to decide when the login is complete and times
out if the machine doesn't reply with a prompt:
$telnet->login($username, $password)or die "Login failed: @{[ $telnet->errmsg() ]}\n";
To run a program and gather its output, use the
cmd method. Pass it the
string to send, and it returns the output of the command. In list context,
it returns one line per list element. In scalar context, it returns one
long line. It waits for the Prompt before returning.
You can separate the sending of the command from the reception of its
output with the print and
waitfor methods. This is
somewhat similar to Expect. The waitfor method takes either a single string containing a Perl regular expression
match operator:
$telnet->waitfor('/--more--/');
or named arguments. Timeout lets you specify a timeout to override the
default, Match is a string containing a match operator as above, and String
is a literal string to find:
$telnet->waitfor(String => 'greasy smoke', Timeout => 30);
In scalar context, waitfor returns true if the pattern or string was
found. If it is not found before timeout occures, the Errmode action is performed. In list context,
it returns two strings: all the text before the match, and the text that
matched.
See also the documentation for the
Net::Telnet module from CPAN; RFCs
854-856, as amended by later RFCs
Hi,
I'm trying to login to a router using telnet and EXPECT, to backup the
router config.
When I'm connecting to the device via telnet, everything is ok, but
when I'm
using a perl/expect-Script to connect, the router asks "Press any key
to
continue", even before the login prompt.
*** via telnet commandline:
# telnet 1.2.3.4
Trying 1.2.3.4...
Connected to 1.2.3.4.
Escape character is '^]'.
One200
Username:
*** via script
# ./save-cpe.pl
Trying 1.2.3.4...
Connected to 1.2.3.4.
Escape character is '^]'.
One200
Press any key to continue (Q to quit)
This is the perl code I spawn telnet with:
$telnet = Expect->spawn('telnet', $ipaddr)
or error_exit(11, "....");
Looks like the router thinks the screen height is just a few lines?
Any ideas?
Thanks,
Re: "expect" spawns telnet -- screen height
> This is the perl code I spawn telnet with:
>
> $telnet = Expect->spawn('telnet', $ipaddr)
> or error_exit(11, "....");
>
> Looks like the router thinks the screen height is just a few
lines?
OK, I've found out that the following code works ok when run
from a bash
shell:
my $telnet = new Expect;
$telnet->raw_pty(1);
if (defined ($telnet->slave)) {
$telnet->slave->clone_winsize_from(\*STDIN);
}
$telnet->spawn('telnet', $ipaddr)
or error_exit(11, ".....");
Unfortunately, I'm running this script from a PHP Page, NOT
from a bash
shell... perl teminates without any hint when reaching the line
"$telnet->slave->clone_winsize_from(\*STDIN);".
Any Idea how to set the winsize to e.g. 80x25 without cloning
it or where to
clone it from when run from a PHP script?
Re: "expect" spawns telnet -- screen height
My solution, based on Jens script, is not very elegant,
but it works
from crontab (for example) :
open TTY,"/dev/console" or die "not connected to a terminal\n";
$telnet->slave->clone_winsize_from(\*TTY);
close TTY;
Daniel
--
dpratlong
>Suppose you needed to open a connection to a remote host from within
your perl program. One thing you would probably think of doing at first
is the following:
open TELNET "|telnet $hostname"; print TELNET "$username\n"; print
TELNET "$password\n"; ...
Unfortunately, if you try this, you'll find it doesn't work. The telnet
program connects to the remote host but it completely ignores any commands
you pipe to it. That's because the telnet program reads its input only
from the terminal and not from standard input.
The most cunning among you might then think a workaround for this: Open
a socket to port 23 (the default telnet port) of the remote machine
and write directly to it, thus, bypassing the telnet program altogether.
Well, although that might sound like a neat idea, it's not. And that's
because the telnet protocol requires that certain control data be exchanged
between the two machines by sending them along through the same socket
connection.
So, it turns out that the problem is much more complicated than it seemed
at first. We don't just need to write code to perform socket I/O, but
also we need to write code that speaks the TELNET protocol. This is
the bad news. The good news is that this code has already been written,
and that its author was kind enough to bundle it in a useful module,
Net::Telnet, available at CPAN.
Net::Telnet
Using Net::Telnet is pretty straightforward and simple. Let's first
see a no-thrills example:
use Net::Telnet; $telnet = new Net::Telnet ( Timeout=>10, Errmode=>'die');
$telnet->open('camel.perlfect.com'); $telnet->waitfor('/login: $/i');
$telnet->print('bilbo'); $telnet->waitfor('/password: $/i'); $telnet->print('baggins');
$telnet->waitfor('/\$ $/i'); $telnet->print('who'); $output = $telnet->waitfor('/\$
$/i'); print $output;
This simple program connects to camel.perlfect.com with username and
password, 'bilbo' and 'baggins' respectively, and the issues the command
'who' to get a list of logged in users. It then retrieves and prints
the output. Although the code is self explanatory, here are a few things
worth of noting:
- The Errmode option in the constructor for the telnet
object specifies what kind of behaviour we want the object to have
when it encounters an error. die means that the program will die
with an error message. The other option is return. This will cause
the method that caused the error to return a false value. The error
message can then be retrieved from Net::Telnet->errmsg.
- The method waitfor() takes a regular expression as
an argument and tries to match it in the stream that is transmitted
from the remote host. Upon a successful match, the method returns
all input before the match.
Shortcuts
You might notice that issuing commands involves repeating print()
and waitfor() calls in a very much similar manner. We print
a command and then we try to match a shell prompt. Net::Telnet
provides a very nice mode of operation that rids you of some of the
repetitive tt. All you need to do is to specify the regular expression
that matches a prompt as a parameter in the object's constructor and
then use the cmd() method to issue commands. Similarly to command issuing,
Net::Telnet provides a handy method to simplify the login process,
namely login(). The following example demonstrates these shortcuts.
use Net::Telnet; $telnet = new Net::Telnet ( Timeout=>10, Errmode=>'die'
Prompt => '/\$ $/i'); $telnet->open('camel.perlfect.com'); $telnet->login('bilbo',
'baggins'); print $telnet->cmd('who');
This does the same as the previous example, but with much less typing.
Note that the login() method matches the login and password
prompts with the regular expressions /(login|username)[: ]*$/i
and /password[: ]*$/i respectively.
So far we have covered the basics of the Net::Telnet module, enough
to get you going with your first telnetting scripts. The module is rich
with other features, so make sure you take the time to have a look at
the documentation.
Happy TELNETing!
- The Net::Telnet documentation that comes with its distribution
(Net::Telnet comes as part of the libnet bundle at CPAN) covers
Simple Telnet Automation
Using Expect
Using perl to
connect to remote hosts via telnet.
Perl Cookbook Solutions and ... - Google Book Search
O'Reilly -
Safari Books Online - 1565922433 - Perl Cookbook
Copyright © 1996-2009 by Dr. Nikolai Bezroukov.
www.softpanorama.org was
created as a service to the UN Sustainable Development Networking Programme (SDNP)
in the author free time.
Submit
comments This document is an industrial compilation designed and created
exclusively for educational use and is placed under the copyright of the
Open Content License(OPL).
Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made
for educational purposes only in compliance with the fair use doctrine.
Disclaimer:
- The statements, views and opinions presented on
this web page are those of the author and are not endorsed by, nor do they necessarily
reflect, the opinions of the author present and former employers, SDNP or any other
organization the author may be associated with.
- We do not warrant the correctness of the information provided or its
fitness for any purpose
- In no way this site is associated with or endorse cybersquatters
using
the term "softpanorama" with other main or country domains (e.g. softpanorama.com) with
bad faith intent to profit from the goodwill belonging to
someone else.
Last modified:
November 26, 2009