使用 bash 脚本自动化 telnet 会话

我正在使用 Bash 脚本自动化一些 telnet相关的任务。 一旦自动化,用户就不会与 telnet进行交互(也就是说它将完全自动化)

剧本大概是这样的:

# execute some commands on the local system
# access a remote system with an IP address: 10.1.1.1 (for example)


telnet 10.1.1.1


# execute some commands on the remote system
# log all the activity (in a file) on the Local system
# exit telnet
# continue on with executing the rest of the script.

我在这里面临两个问题:

  1. 如何从脚本执行远程系统上的命令(没有人工交互) ?

    根据我对一些测试代码的经验,我能够推断出,当执行 telnet 10.1.1.1时,telnet 进入交互式会话,脚本中的后续代码行在本地系统上执行。如何在远程系统而不是本地系统上运行代码行?

  2. 我无法获得本地系统上 telnet会话中活动的日志文件。我使用的 stdout 重定向在远程系统上创建了一个副本(我不想执行将日志复制到本地系统的复制操作)。我如何实现这个功能?

324518 次浏览

Write an expect script.

Here is an example:

#!/usr/bin/expect


#If it all goes pear shaped the script will timeout after 20 seconds.
set timeout 20
#First argument is assigned to the variable name
set name [lindex $argv 0]
#Second argument is assigned to the variable user
set user [lindex $argv 1]
#Third argument is assigned to the variable password
set password [lindex $argv 2]
#This spawns the telnet program and connects it to the variable name
spawn telnet $name
#The script expects login
expect "login:"
#The script sends the user variable
send "$user "
#The script expects Password
expect "Password:"
#The script sends the password variable
send "$password "
#This hands control of the keyboard over to you (Nice expect feature!)
interact

To run:

./myscript.expect name user password

Use ssh for that purpose. Generate keys without using a password and place it to .authorized_keys at the remote machine. Create the script to be run remotely, copy it to the other machine and then just run it remotely using ssh.

I used this approach many times with a big success. Also note that it is much more secure than telnet.

While I'd suggest using expect, too, for non-interactive use the normal shell commands might suffice. telnet accepts its command on stdin, so you just need to pipe or write the commands into it through heredoc:

telnet 10.1.1.1 <<EOF
remotecommand 1
remotecommand 2
EOF

(Edit: Judging from the comments, the remote command needs some time to process the inputs or the early SIGHUP is not taken gracefully by telnet. In these cases, you might try a short sleep on the input:)

{ echo "remotecommand 1"; echo "remotecommand 2"; sleep 1; } | telnet 10.1.1.1

In any case, if it's getting interactive or anything, use expect.

Play with tcpdump or wireshark and see what commands are sent to the server itself

Try this

printf (printf "$username\r\n$password\r\nwhoami\r\nexit\r\n") | ncat $target 23

Some servers require a delay with the password as it does not hold lines on the stack

printf (printf "$username\r\n";sleep 1;printf "$password\r\nwhoami\r\nexit\r\n") | ncat $target 23**

Telnet is often used when you learn HTTP protocol. I used to use that script as a part of my web-scraper:

echo "open www.example.com 80"
sleep 2
echo "GET /index.html HTTP/1.1"
echo "Host: www.example.com"
echo
echo
sleep 2

let's say the name of the script is get-page.sh then:

get-page.sh | telnet

will give you a html document.

Hope it will be helpful to someone ;)

You can use expect scripts instaed of bash. Below example show how to telnex into an embedded board having no password

#!/usr/bin/expect


set ip "<ip>"


spawn "/bin/bash"
send "telnet $ip\r"
expect "'^]'."
send "\r"
expect "#"
sleep 2


send "ls\r"
expect "#"


sleep 2
send -- "^]\r"
expect "telnet>"
send  "quit\r"
expect eof

This worked for me..

I was trying to automate multiple telnet logins which require a username and password. The telnet session needs to run in the background indefinitely since I am saving logs from different servers to my machine.

telnet.sh automates telnet login using the 'expect' command. More info can be found here: http://osix.net/modules/article/?id=30

telnet.sh

#!/usr/bin/expect
set timeout 20
set hostName [lindex $argv 0]
set userName [lindex $argv 1]
set password [lindex $argv 2]


spawn telnet $hostName


expect "User Access Verification"
expect "Username:"
send "$userName\r"
expect "Password:"
send "$password\r";
interact

sample_script.sh is used to create a background process for each of the telnet sessions by running telnet.sh. More information can be found in the comments section of the code.

sample_script.sh

#!/bin/bash
#start screen in detached mode with session-name 'default_session'
screen -dmS default_session -t screen_name
#save the generated logs in a log file 'abc.log'
screen -S default_session -p screen_name -X stuff "script -f /tmp/abc.log $(printf \\r)"
#start the telnet session and generate logs
screen -S default_session -p screen_name -X stuff "expect telnet.sh hostname username password $(printf \\r)"
  1. Make sure there is no screen running in the backgroud by using the command 'screen -ls'.
  2. http://www.gnu.org/software/screen/manual/screen.html#Stuff to read more about screen and its options.
  3. '-p' option in sample_script.sh preselects and reattaches to a specific window to send a command via the ‘-X’ option otherwise you get a 'No screen session found' error.
#!/bin/bash
ping_count="4"
avg_max_limit="1500"
router="sagemcom-fast-2804-v2"
adress="192.168.1.1"
user="admin"
pass="admin"


VAR=$(
expect -c "
set timeout 3
spawn telnet "$adress"
expect \"Login:\"
send \"$user\n\"
expect \"Password:\"
send \"$pass\n\"
expect \"commands.\"
send \"ping ya.ru -c $ping_count\n\"
set timeout 9
expect \"transmitted\"
send \"exit\"
")


count_ping=$(echo "$VAR" | grep packets | cut -c 1)
avg_ms=$(echo "$VAR" | grep round-trip | cut -d '/' -f 4 | cut -d '.' -f 1)


echo "1_____ping___$count_ping|||____$avg_ms"
echo "$VAR"

Here is how to use telnet in bash shell/expect

#!/usr/bin/expect
# just do a chmod 755 one the script
# ./YOUR_SCRIPT_NAME.sh $YOUHOST $PORT
# if you get "Escape character is '^]'" as the output it means got connected otherwise it has failed


set ip [lindex $argv 0]
set port [lindex $argv 1]


set timeout 5
spawn telnet $ip $port
expect "'^]'."

Following is working for me... put all of your IPs you want to telnet in IP_sheet.txt

while true
read a
do
{
sleep 3
echo df -kh
sleep 3
echo exit
} | telnet $a
done<IP_sheet.txt

Script for obtain version of CISCO-servers:

#!/bin/sh


servers='
192.168.34.1
192.168.34.3
192.168.34.2
192.168.34.3
'
user='cisco_login'
pass='cisco_password'


show_version() {
host=$1
expect << EOF
set timeout 20
set host $host
set user $user
set pass $pass
spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect -re ".*#"
send "show version\r"
expect -re ".*-More-.*"
send " "
expect -re ".*#"
send "exit\r"
EOF
}


for ip in $servers; do
echo '---------------------------------------------'
echo "$ip"
show_version $ip | grep -A3 'SW Version'
done

Here is a solution that will work with a list of extenders. This only requires bash - some of the answers above require expect and you may not be able to count on expect being installed.

#!/bin/bash


declare -a  Extenders=("192.168.1.48" "192.168.1.50" "192.168.1.51")
# "192.168.1.52" "192.168.1.56" "192.168.1.58" "192.168.1.59" "192.168.1.143")
sleep 5
# Iterate the string array using for loop
for val in ${Extenders[@]}; do
{ sleep 0.2; echo "root"; sleep 0.2; echo "ls"; sleep 0.2; }  | telnet $val
done

The answer by @thiton was helpful but I wanted to avoid the sleep command. Also telnet didn't exit the interactive mode, so my script got stuck.

I solved that by sending telnet command with curl (which seems to wait for the response) and by explicitly telling telnet to quit like this:

curl telnet://10.1.1.1:23 <<EOF
remotecommand 1
remotecommand 2
quit
EOF