I have tcl expect script to daily check some version on the network devices.
#!/usr/bin/expect --
set env(TERM) vt100
set timeout 5
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 2]
set success 1
#login script
log_user 1
spawn ssh $username@$hostname
expect {
"Connection refused" {
spawn telnet $hostname
expect {
"?sername:" {
if { $success == 0 } {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$username\r"
}
exp_continue
}
"?assword:" {
send "$password\r"
exp_continue
}
timeout {
log_user 1
puts "error could not ssh or telnet devices"
exit 1;
exp_continue
}
"#" {
send "terminal length 0\r"
}
}
exp_continue
}
timeout {
spawn telnet $hostname
expect {
timeout {
log_user 1
puts "error could not ssh or telnet devices"
exit 1;
exp_continue
}
"?..." {
log_user 1
puts "error could not ssh or telnet devices"
exit 1;
exp_continue
}
"?sername:" {
if { $success == 0 } {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$username\r"
}
exp_continue
}
"?assword:" {
send "$password\r"
exp_continue
}
"#" {
send "terminal length 0\r"
}
}
exp_continue
}
"continue connecting (yes/no)?" {
send "yes\r"
exp_continue
}
"?assword:" {
if { $success == 0 } {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$password\r"
}
exp_continue
}
"$ " {
send "ssh keygen -R $hostname\r"
exp_continue
}
"#" {
send "terminal length 0\r"
}
}
#execute script
expect "#"
send "\r"
expect "#"
log_user 1
send "show version\r"
expect "#"
send "exit\r"
My expect script working like this,
and the problem is, my expect program from could not work if ssh key on remote devices is changed.
[linux]$ ./sshtelnet.tcl mine password 1.1.1.1
spawn ssh mine@1.1.1.1
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
83:24:a5:c4:2c:98:0d:0b:d6:ad:cb:74:12:7e:84:83.
Please contact your system administrator.
Add correct host key in /home/linux/.ssh/known_hosts to get rid of this message.
Offending key in /home/linux/.ssh/known_hosts:152
RSA host key for 1.1.1.1 has changed and you have requested strict checking.
Host key verification failed.
expect: spawn id exp4 not open
while executing
"expect "#""
(file "./sshtelnet.tcl" line 106)
When the remote host identification has changed, the ssh process terminates. Assuming you know that this is not because "someone is doing something nasty", you want to execute the "ssh-keygen -R $hostname" locally, not send it to the spawned ssh process. After cleaning up the offending key, you have to spawn the ssh command again.
The easiest way to be able to repeat the ssh command is to put things in procs:
proc connectssh {username password hostname} {
global spawn_id
set success 1
spawn ssh $username@$hostname
expect {
"Connection refused" {
connecttelnet $username $password $hostname
}
timeout {
connecttelnet $username $password $hostname
}
"continue connecting (yes/no)?" {
send "yes\r"
exp_continue
}
"?assword:" {
if {$success == 0} {
log_user 1
puts "error user or password incorrect"
exit 1;
} else {
incr success -1
send "$password\r"
}
exp_continue
}
"Host key verification failed" {
wait
exec ssh-keygen -R $hostname
connectssh $username $password $hostname
}
"#" {
send "terminal length 0\r"
}
}
}
proc conecttelnet {username password hostname} {
global spawn_id
spawn telnet $hostname
expect {
# ...
}
}
set env(TERM) vt100
set timeout 5
lassign $argv username password hostname
log_user 1
connectssh $username $password $hostname
# The rest of your script