Search code examples
telnetexpect

Expect script telnet timeout issue


The following scripts telnet into various devices called from a txt file and then run a command, log the output and then exits. However when an incorrect IP address is used the script displays the username and password entered and this is visible in the log file which is not ideal. Any idea how to insert a timeout to prevent this?

#telnet.exp
######################################################

#!/usr/bin/expect -f

# Set variables
set hostname [lindex $argv 0]
set username [lindex $argv 2]
set password [lindex $argv 1]

# Log the output
log_file -a ~/configuration-telnet.log

# Which device we are working on and at what time
send_user "\n"
send_user ">>>>>  Working on $hostname @ [exec date] <<<<<\n"
send_user "\n"

spawn telnet $hostname
expect "Username:"
send "$username\n"

expect "Password:"
send "$password\n"
expect "#"

send "term len 0\r"
send "show running-config\r"
expect "end\r"
send "\r"
send "exit\r"

########################################################
#telnet.sh
########################################################
#!/bin/bash
echo -n "Username:"
read -s -e username
echo -ne '\n'
echo -n "Password:"
read -s -e password
echo -ne '\n'
# Feed the expect script a device list & the collected passwords
for device in `cat telnet-device-list.txt`; do
./telnet.exp $device $password $username;
done

Solution

  • In order to make the timeout event, you can add it as pattern which is a in-built command to match the timeout.

    Basic idea can be something like,

    expect {
        pattern {some_action_here} 
        timeout {puts "timeout_here"}
    }
    

    To make it common for all sort of commands, it can be generalized with expect_after command.

    expect_after timeout {puts "timeout happened in the script"; exit 0}
    

    Just as I have mentioned before, I recommend you to use expect after each send command.

    So, your script can be modified as follows,

    #!/usr/bin/expect -f
    
    # Set variables
    set hostname [lindex $argv 0]
    set username [lindex $argv 2]
    set password [lindex $argv 1]
    
    # Log the output
    log_file -a ~/configuration-telnet.log
    
    # Which device we are working on and at what time
    send_user "\n"
    send_user ">>>>>  Working on $hostname @ [exec date] <<<<<\n"
    send_user "\n"
    
    expect_after timeout {puts "Timeout happened; So, exiting....";exit 0}
    
    spawn telnet $hostname
    expect "Username:" 
    send "$username\r"
    expect "Password:"
    send "$password\r"
    expect "#" 
    send "term len 0\r"
    expect "#" 
    send "show running-config\r"
    expect "end"
    send "\r"
    expect "#" 
    send "exit\r"; 
    # After sending 'exit' telnet session will be closed
    # So, waiting for 'eof'
    expect eof
    

    If you deliberately want to write separate timeout actions then you can re-write it like,

    expect {
        timeout { puts "username timeout"; exit 0}
        "Username:"
    } 
    send "$username\r"
    expect {
        timeout { puts "password timeout"; exit 0}
        "Password:"
    }
    send "$password\r"
    expect {
        timeout { puts "prompt timeout"; exit 0}
        "#" 
    }
    

    Note :

    The default timeout value is 10 seconds. It can be even changed as

    set timeout 60; # Timeout value of 1 min