|
Introduction to TelnetTelnet
is the main Internet protocol for creating a connection
with a remote machine. It gives the user the opportunity
to be on one computer system and do work on another, which
may be across the street or thousands of miles away. Where
modems are limited, in the majority, by the quality of telephone
lines and a single connection, telnet provides a connection
that's error-free and nearly always faster than the latest
conventional modems. Many telnet clients also include a
third option, the port on which the connection should take
place. Normally, port 23 is the default telnet port; the
user never has to think about it. But sometimes it's desirable
to telnet to a different port on a system, where there may
be a service available, or to aid in debugging a problem. To open the
connection, type:
telnet your.system.name
The escape character, in this example ^] (Control-]), is the character that will let you go back to the local system to close the connection, suspend it, etc. To close this connection, the user would type ^], and respond to the telnet> prompt with the command close. Local documentation should be checked for information on specific commands, functions, and escape character that can be used. Once a connection is established,
a welcome message is usually printed by the server and then the user
must log in. The server will request that the user enter his/her username
and password. After the user has entered a valid username and password they are given
the command prompt. The command prompt usually contains user name and
the name of the server followed by a symbol such as a $, #, or %. However,
the prompt may contain more information like the current directory,
or no information at all and just a symbol. Here are some examples: From the command prompt the user can execute shell commands which alter
the state of the machine or run programs. Each system is different and
can use any number of shells that have different command structures.
One that is universal is the exit command. simply type exit
or logout
to disconnect from the remove server. Here is a complete telnet conversation. Lines starting with a C: are written by the client and lines starting with a S: are written by the server. S: Welcome to sturm.bright-blade.net S: Linux Mandrake release 7.0 (Air) S: Kernel 2.2.14-15mdk on an i686 S: login: C: bilbo S: Password: C: baggins <- this is sometimes all *s or not echoed to the screen at all S: Last login: Thu Apr 18 09:23:06 from 147.129.100.172 S: [bilbo@sturm bilbo]$ C: exit See Example 1 in the Interactions section for a full interaction. |
Coding a Telnet Client with PerlIn order to implement a telnet client using Perl, we must first install the Net-Telnet module. Open a DOS command window and enter the following: C:\> cd \Perl\bin C:\> ppm PPM> install net-telnet PPM> exit Once you have the net-telnet module installed, create a new text file titled telnet1.pl. Start out by typing the following lines to create a new telnet data structure. use Net::Telnet;
$telnet = new Net::Telnet ( Timeout=>20,
Errmode=>'die');
Now you need to open the connection by using the following function: $telnet->open('www.bright-blade.net');
Following the telnet conversation described above, we need to give the remote host our username and password in order to login. Then before issuing any commands we need to wait for the command prompt. Since different servers use different prompts we can use a regular expression to recognize any prompt. The phrase "[\$%#>] " means try to match one of the following characters (the $ is a special character in Perl so it must be preceded by a \) followed by a space--do not forget the space! $telnet->waitfor('/login: $/i');
telnet->print('bilbo');
$telnet->waitfor('/password: $/i');
$telnet->print('baggins');
$telnet->waitfor('/[\$%#>] $/i');
Now that we are connected we can send a command to the receiving end and print the results to the screen: $telnet->print('who');
$output = $telnet->waitfor('/[\$%#>] $/i');
We do not have to close the connection because once the script ends the connection is terminated. However, if you want, you can print "exit" or "logout" to the socket. Save your file and execute it by typing perl telnet1.pl at the command line. If all is well, it should print the users currently connected to that server including yourself. See Example 2 in the Interactions section to see the output of this script. A simpler way of doing this is outlined in the following code. Using functions built into the net-telnet module, we can make a connection and execute commands very simply. Create a new file called telnet2.pl and type this script. Note that the prompt is defined when creating the telnet structure so it is possible to just call commands without waiting for the prompt each time. use Net::Telnet;
$telnet = new Net::Telnet ( Timeout=>20,
Errmode=>'die',
Prompt => '/[\$%#>] $/i');
$telnet->open('www.bright-blade.net');
$telnet->login('bilbo', 'baggins');
print $telnet->cmd('who');
|
A Telnet ExampleNow that you understand the basics of using the net-telnet module we can make a more complex script. Follow the following steps to create a script that uses a telnet connection to retrieve the contents of a file. First we need to create and initialize some variables that we are going to use. You can substitute any of these for an existing account you know of. (Note: Kevin, I have created this account on my server so you can test the script) ## define variables
my ($block, $filename, $host, $hostname, $k_per_sec, $line,
$num_read, $passwd, $prevblock, $prompt, $size, $size_bsd,
$size_sysv, $start_time, $total_time, $username);
## initialize variables
$hostname = "www.bright-blade.net";
$username = "bilbo";
$passwd = "baggins";
$filename = ".bashrc";
Next we need to establish a connection. I have chosen to use STDERR to print status messages to the screen so that the contents of the file can be redirected using a pipe to an output file without including the messages. These messages are not necessary, but they are excelent for debugging. ## Connect and login.
use Net::Telnet ();
$host = new Net::Telnet (Timeout =>60,
Errmode=>'die',
Prompt =>'/[\$%#>_] $/i');
$host->open($hostname);
print STDERR "connected...\n";
print STDERR "logging in: $username...";
$host->login($username,$passwd);
print STDERR "\tdone\n";
When sending commands to the remote host you may have noticed that the command prompt is always the last piece of text returned to the client. In order to remove this from our file we must change it to something we know will not be included in the file. That way we can cut it off after the file is retrieved. Here is the code to change the command prompt in a bash shell. If you are using a different shell, the command may be different. ## Make sure prompt won't match anything in send data.
print STDERR "switching prompt...";
$prompt = 'funkyPrompt% ';
$host->prompt("/$prompt\$/");
$host->cmd("export PS1='$prompt'");
print STDERR "\tdone\n";
Now we need to obtain the file size so that when we finish reading it we can check to see that we have received the entire file. This is done by using the ls -l command which will return all the information about the file. We then parse that information for a variable containing only digits which should be the file size. ## Get size of file.
print STDERR "getting file size...";
($line) = $host->cmd("/bin/ls -l $filename");
($size_bsd, $size_sysv) = (split ' ', $line)[3,4];
if ($size_sysv =~ /^\d+$/) {
$size = $size_sysv;
}
elsif ($size_bsd =~ /^\d+$/) {
$size = $size_bsd;
}
else {
die "$filename: no such file on $hostname";
}
print STDERR "\tdone\n";
Now is the tricky part: getting the file. Basicly we have the server echo the file to the client using the cat function then read it one line at a time until the prompt is read. We also want to time how long this takes by storing the current time value in $start_time. Once the file is retrieved we can close the connection. ## Start sending the file.
print STDERR "getting file...";
binmode STDOUT;
$host->binmode(1);
$host->print("/bin/sh -c 'stty raw; cat $filename'");
$host->getline; # discard echoed back line
## Read file a block at a time.
$num_read = 0;
$prevblock = '';
$start_time = time;
while (($block = $host->get) and ($block !~ /$prompt$/o)) {
if (length $block >= length $prompt) {
print $prevblock;
$num_read += length $prevblock;
$prevblock = $block;
}
else {
$prevblock .= $block;
} }
$host->close;
print STDERR "\t\tdone\n";
Next, we need to remove the prompt from the last line by swapping it with an empty string before we print it. Then we can check the overall length of the file to see if it matches the size we determined above. ## Print last block without trailing prompt.
$prevblock .= $block;
$prevblock =~ s/$prompt$//;
print $prevblock;
$num_read += length $prevblock;
die "error: expected size $size, received size $num_read\n"
unless $num_read == $size;
Finally, we can print the elapsed time and the size of the file. ## Print totals.
$total_time = (time - $start_time) || 1;
$k_per_sec = ($size / 1024) / $total_time;
$k_per_sec = sprintf "%3.1f", $k_per_sec;
warn("$num_read bytes received in $total_time seconds ",
"($k_per_sec Kbytes/s)\n");
exit;
Once you have entered in all the code above save it as getfile.pl. To run it you can do two things: print it to the screen or print it to a file. See Examples 3 and 4 in the Interactions section. |
Telnet InteractionsExample 1 - a telnet login[chuyler1@sturm chuyler1]$ telnet www.bright-blade.net Trying 24.24.22.198... Connected to www.bright-blade.net. Escape character is '^]'. Welcome to sturm.bright-blade.net Linux Mandrake release 7.0 (Air) Kernel 2.2.14-15mdk on an i686 login: bilbo Password: Last login: Wed Apr 17 21:19:09 from 192.168.1.1 [bilbo@sturm bilbo]$ who chuyler1 tty1 Apr 17 21:12 chuyler1 pts/0 Apr 17 21:17 bilbo pts/1 Apr 17 21:19 [bilbo@sturm bilbo]$ exit Connection closed by foreign host. Example 2 - telnet1.pl outputC:\Perl\bin>perl telnet1.pl connected... entered username... entered password... logged in! chuyler1 tty1 Apr 17 21:12 bilbo pts/0 Apr 18 08:27 [bilbo@sturm bilbo] Example 3 - telnet2.pl outputC:\Perl\bin>perl telnet2.pl connected... logged in! chuyler1 tty1 Apr 17 21:12 bilbo pts/0 Apr 18 08:27 [bilbo@sturm bilbo] Example 4 - getfile.pl output 1C:\Perl\bin>perl getfile.pl
connected...
logging in: bilbo... done
switching prompt... done
getting file size... done
getting file... done
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
BASH_ENV=$HOME/.bashrc
USERNAME=""
export USERNAME BASH_ENV PATH
230 bytes received in 1 seconds (0.2 Kbytes/s)
Example 5 - getfile.pl output 2 (contents of file stored in myfile.txt)C:\Perl\bin>perl getfile.pl > myfile.txt connected... logging in: bilbo... done switching prompt... done getting file size... done getting file... done 230 bytes received in 1 seconds (0.2 Kbytes/s) |
Appendixtelnet1.pluse Net::Telnet;
$telnet = new Net::Telnet ( Timeout=>20,
Errmode=>'die');
$telnet->open('www.bright-blade.net');
print "connected...\n";
$telnet->waitfor('/login: $/i');
$telnet->print('bilbo');
print "entered username...\n";
$telnet->waitfor('/password: $/i');
$telnet->print('baggins');
print "entered password...\n";
$telnet->waitfor('/[\$%#>_] $/i');
print "logged in!\n";
$telnet->print('who');
$output = $telnet->waitfor('/\$ $/i');
print $output;
telnet2.pluse Net::Telnet;
$telnet = new Net::Telnet ( Timeout=>20,
Errmode=>'die',
Prompt => '/\$ $/i');
$telnet->open('www.bright-blade.net');
print "connected...\n";
$telnet->login('bilbo', 'baggins');
print "logged in!\n";
print $telnet->cmd('who');
getfile.pl## define variables
my ($block, $filename, $host, $hostname, $k_per_sec, $line,
$num_read, $passwd, $prevblock, $prompt, $size, $size_bsd,
$size_sysv, $start_time, $total_time, $username);
## initialize variables
$hostname = "www.bright-blade.net";
$username = "bilbo";
$passwd = "baggins";
$filename = ".bashrc";
## Connect and login.
use Net::Telnet ();
$host = new Net::Telnet (Timeout =>60,
Errmode=>'die',
Prompt =>'/[\$%#>_] $/i');
$host->open($hostname);
print STDERR "connected...\n";
print STDERR "logging in: $username...";
$host->login($username,$passwd);
print STDERR "\tdone\n";
## Make sure prompt won't match anything in send data.
print STDERR "switching prompt...";
$prompt = 'funkyPrompt% ';
$host->prompt("/$prompt\$/");
$host->cmd("export PS1='$prompt'");
print STDERR "\tdone\n";
## Get size of file.
print STDERR "getting file size...";
($line) = $host->cmd("/bin/ls -l $filename");
($size_bsd, $size_sysv) = (split ' ', $line)[3,4];
if ($size_sysv =~ /^\d+$/) {
$size = $size_sysv;
}
elsif ($size_bsd =~ /^\d+$/) {
$size = $size_bsd;
}
else {
die "$filename: no such file on $hostname";
}
print STDERR "\tdone\n";
## Start sending the file.
print STDERR "getting file...";
binmode STDOUT;
$host->binmode(1);
$host->print("/bin/sh -c 'stty raw; cat $filename'");
$host->getline; # discard echoed back line
## Read file a block at a time.
$num_read = 0;
$prevblock = '';
$start_time = time;
while (($block = $host->get) and ($block !~ /$prompt$/o)) {
if (length $block >= length $prompt) {
print $prevblock;
$num_read += length $prevblock;
$prevblock = $block;
}
else {
$prevblock .= $block;
} }
$host->close;
print STDERR "\t\tdone\n";
## Print last block without trailing prompt.
$prevblock .= $block;
$prevblock =~ s/$prompt$//;
print $prevblock;
$num_read += length $prevblock;
die "error: expected size $size, received size $num_read\n"
unless $num_read == $size;
## Print totals.
$total_time = (time - $start_time) || 1;
$k_per_sec = ($size / 1024) / $total_time;
$k_per_sec = sprintf "%3.1f", $k_per_sec;
warn("$num_read bytes received in $total_time seconds ",
"($k_per_sec Kbytes/s)\n");
exit;
|
| www.bright-blade.net |