tự động hóa phiên telnet bằng cách sử dụng các tập lệnh bash


80

Tôi đang làm việc để tự động hóa một số tác vụ liên quan đến telnet, sử dụng các tập lệnh Bash. Sau khi tự động hóa sẽ không có sự tương tác của người dùng với telnet. (nghĩa là nó sẽ hoàn toàn tự động)

các tập lệnh trông giống như sau:

# 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.

Có 2 vấn đề tôi đang gặp phải ở đây:

  1. Làm thế nào để thực hiện các lệnh trên hệ thống từ xa từ tập lệnh (không có sự tương tác của con người)?

    Từ kinh nghiệm của tôi với một số mã thử nghiệm, tôi có thể suy ra rằng khi telnet 10.1.1.1 được thực thi, telnet sẽ chuyển sang một phiên tương tác và các dòng mã tiếp theo trong tập lệnh được thực thi trên hệ thống cục bộ. Làm cách nào để chạy các dòng mã trên hệ thống từ xa thay vì trên hệ thống cục bộ?

  2. Tôi không thể lấy tệp nhật ký cho hoạt động trong phiên telnet trên hệ thống cục bộ. Chuyển hướng stdout mà tôi đã sử dụng tạo một bản sao trên hệ thống từ xa (tôi không muốn thực hiện thao tác sao chép để sao chép nhật ký vào hệ thống cục bộ). Làm cách nào để đạt được chức năng này?

Câu trả lời:


77

Viết expectkịch bản.

Đây là một ví dụ:

#!/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

Chạy:

./myscript.expect name user password

2
'mong đợi' chủ yếu dành cho các phiên tương tác. Những gì tôi muốn là một phiên tự động không tương tác. vấn đề tôi đang gặp phải là tôi không thể chạy các tập lệnh trên hệ thống từ xa (thông qua telnet) vì tất cả các dòng theo sau telnet 10.1.1.1 được thực thi trên máy cục bộ chứ không phải máy tôi đang truy cập.
khan

3
Như Thomas Telensky đã chỉ ra, tùy thuộc vào nhu cầu của bạn, ssh cuối cùng dễ dàng hơn. Nhưng mong đợi có thể hoàn toàn không tương tác. Tôi giả định rằng ý của bạn là tất cả các dòng theo sau telnet là những gì bạn muốn được thực thi trên máy từ xa trong trường hợp đó chỉ cần thêm chúng vào tập lệnh mong đợi như gửi lệnh và xóa lệnh tương tác. Nhưng ssh dễ dàng hơn và an toàn hơn.
joemooney

2
đủ công bằng. Tôi sẽ sử dụng kỳ vọng cho nhiệm vụ này.
khan

1
một bổ sung tốt khác là đọc này - elenako.com/2013/04/04/… , tập lệnh được cung cấp không có \rtrình tự ở cuối lệnh và khi tôi nhấp vào enter thì nó không hoạt động vì một số lý do
llamerr

88

Mặc dù tôi cũng khuyên bạn nên sử dụng kỳ vọng, đối với việc sử dụng không tương tác, các lệnh shell bình thường có thể đủ. Telnet chấp nhận lệnh của nó trên stdin, vì vậy bạn chỉ cần nhập hoặc viết các lệnh vào đó:

telnet 10.1.1.1 <<EOF
remotecommand 1
remotecommand 2
EOF

(Chỉnh sửa: Đánh giá từ các nhận xét, lệnh từ xa cần một thời gian để xử lý đầu vào hoặc SIGHUP ban đầu không được telnet thực hiện một cách duyên dáng. Trong những trường hợp này, bạn có thể thử một thời gian ngắn trên đầu vào :)

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

Trong mọi trường hợp, nếu nó nhận được tương tác hoặc bất cứ điều gì, hãy sử dụng expect.


2
1 sleeptác phẩm như một giấc mơ ;-) Tôi cũng đã thêm | tee /dev/tty |ở giữa có phiên đầy đủ trên màn hình ;-)
paluh

1
trong trường hợp của tôi, câu trả lời hữu ích nhất, nhưng tôi phải thêmecho -e "command\r";
mf_

1
Làm cách nào để cung cấp mật khẩu cho telnet không tương tác?
Geremia

{ echo "remotecommand 1"; echo "remotecommand 2"; sleep 1; } | telnet 10.1.1.1 : Ví dụ này đáp ứng yêu cầu của tôi. Chỉ muốn biết làm thế nào để chúng tôi thêm kiểm tra lỗi nếu telnet bị lỗi và tập lệnh shell nên exit 1.
Yash

44

Telnet thường được sử dụng khi bạn học giao thức HTTP. Tôi đã từng sử dụng tập lệnh đó như một phần của trình duyệt web của mình:

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

giả sử tên của script là get-page.sh sau đó:

get-page.sh | telnet

sẽ cung cấp cho bạn một tài liệu html.

Hy vọng nó sẽ hữu ích cho ai đó;)


1
Nhận xét hữu ích nhất! Điều này thực sự cho phép bạn tự động gửi các lệnh bằng cách đặt chúng trong một vòng lặp
RomanM

Một bài đăng trợ giúp khác blog.tonycode.com/tech-stuff/http-notes/…
leomeurer

One-liner tương đương: { echo "GET / HTTP/1.1"; echo "Host: www.example.com"; echo; sleep 1; } | telnet www.example.com 80. Lưu ý rằng chế độ ngủ không cần thiết khi bắt đầu (trừ khi bạn sử dụng lệnh mở) và chỉ cần một tiếng vọng trống và chế độ ngủ 1 thay vì 2 ở cuối.
baptx

Nhưng nếu bạn cần phải làm các yêu cầu HTTPS, bạn nên sử dụng netcat, còn được gọi là ncat hoặc nc:{ echo "GET / HTTP/1.1"; echo "Host: example.com"; echo; sleep 1; } | ncat --ssl example.com 443
baptx

12

Điều này đã làm việc cho tôi ..

Tôi đang cố gắng tự động hóa nhiều lần đăng nhập telnet yêu cầu tên người dùng và mật khẩu. Phiên telnet cần phải chạy trong nền vô thời hạn vì tôi đang lưu nhật ký từ các máy chủ khác nhau vào máy của mình.

telnet.sh tự động đăng nhập telnet bằng lệnh 'mong đợi'. Có thể tìm thêm thông tin tại đây: 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 được sử dụng để tạo quy trình nền cho mỗi phiên telnet bằng cách chạy telnet.sh. Thông tin thêm có thể được tìm thấy trong phần bình luận của mã.

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. Đảm bảo rằng không có màn hình nào đang chạy trong backgroud bằng cách sử dụng lệnh 'screen -ls'.
  2. Đọc http://www.gnu.org/software/screen/manual/screen.html#Stuff để đọc thêm về màn hình và các tùy chọn của nó.
  3. Tùy chọn '-p' trong sample_script.sh chọn trước và gắn lại vào một cửa sổ cụ thể để gửi lệnh qua tùy chọn '-X' nếu không bạn sẽ gặp lỗi 'Không tìm thấy phiên màn hình'.

2

Bạn có thể sử dụng các tập lệnh mong đợi được cài đặt sẵn của bash. Ví dụ dưới đây cho thấy làm thế nào để telnex vào một bảng nhúng không có mật khẩu

#!/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

2

Sau đây là hiệu quả đối với tôi ... đặt tất cả các IP của bạn mà bạn muốn telnet vào IP_sheet.txt

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

1
#!/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"

0

Sử dụng ssh cho mục đích đó. Tạo khóa mà không cần sử dụng mật khẩu và đặt nó vào .authorized_keys ở máy từ xa. Tạo tập lệnh để chạy từ xa, sao chép nó vào máy khác và sau đó chỉ cần chạy nó từ xa bằng ssh.

Tôi đã sử dụng phương pháp này nhiều lần với một thành công lớn. Cũng lưu ý rằng nó an toàn hơn nhiều so với telnet.


1
sshchắc chắn an toàn hơn telnet, nhưng một số thiết bị IP không cung cấp sshdịch vụ và dựa vào telnetgiao thức để sử dụng thiết bị.
fduff

2
telnet (chương trình) có thể được sử dụng như một ứng dụng khách cho BẤT KỲ kết nối máy khách / máy chủ dựa trên văn bản nào (hoặc thực tế hơn). Nó có thể được sử dụng để kiểm tra dễ dàng, chẳng hạn như HTTP và IMAP. Đề xuất của @Tomas là thay thế việc sử dụng Telnet (dịch vụ đăng nhập từ xa) bằng SSH. trong khi nhận xét của anh ấy là đúng, nó có lẽ không phải là những gì OP yêu cầu.
Rob Shepherd

Rob, telnet thực sự có thể được sử dụng để kết nối với bất kỳ cổng nào, nhưng hãy xem câu hỏi của OP - trong bối cảnh của anh ấy, anh ấy chỉ muốn sử dụng telnet để đăng nhập (trích dẫn: "thực hiện một số lệnh trên hệ thống từ xa" ). Sử dụng telnet cho mục đích này là rất rủi ro.
TMS

Đây không phải là câu trả lời cho câu hỏi nói cụ thể là 'tự động hóa một số nhiệm vụ liên quan đến telnet' bằng cách sử dụng các tập lệnh hiện có của anh ấy.
FractalSpace

0

Đây là cách sử dụng telnet trong bash shell / mong đợi

#!/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 "'^]'."

0

Tập lệnh cho phiên bản tải xuống của máy chủ CISCO:

#!/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

-4

Chơi với tcpdumphoặc wiresharkvà xem những lệnh nào được gửi đến chính máy chủ

Thử cái này

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

Một số máy chủ yêu cầu độ trễ với mật khẩu vì nó không giữ dòng trên ngăn xếp

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

9
Sự mới mẻ không có lý do gì cho sự thô lỗ. Vui lòng xem Câu hỏi thường gặp stackoverflow.com/faq .
Verbeia

1
không có ý xúc phạm, giống như ... tôi không biết, xin lỗi. Tôi chỉ thấy mọi người sử dụng lệnh mong đợi như một giải pháp. Tôi chỉ muốn mọi người nhận ra rằng có một giải pháp tốt hơn để hiểu những gì bạn đang cố gắng hoàn thành. Lệnh mong đợi không cho bạn biết nó hoạt động như thế nào, nó chỉ là một cách giải quyết khi bạn không biết. Nó là khó hiểu hơn sau đó không. Khi nghi ngờ, hãy đến nguồn. Nếu nguồn không có sẵn và nếu nó là một giao thức mạng, tcpdump, Wirehark, rình mò các gói và làm theo luồng lệnh và bạn sẽ có thể kết hợp một cái gì đó cùng với kiến ​​thức làm việc.
str8

7
Nếu bạn nói như vậy - Tôi là một lập trình viên Mathematica nên nội dung câu trả lời và nhận xét của bạn là một bí ẩn đối với tôi. Nhưng tôi không đơn độc trong việc giải thích từ "những kẻ ngốc" là cố ý xúc phạm. Tôi nghĩ bạn cần dành nhiều thời gian hơn trên trang web và xem cách mọi người cư xử ở đây.
Verbeia
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.