Search code examples
expect

Running SSH through expect, freezes at first character sent after prompt is reached


I am writing an expect script to automate diagnostic SSH sessions against a certain type of IoT devices. The script is run from a jump host, where the user running the script needs elevation to access the keyfile used for SSH authentication.

The authentication works and I reach the IoT device's shell prompt, but as I send a command to the prompt (ls -l in the script below) the output freezes and nothing more happens.

Expect script rundiag.expect:

#!/usr/bin/expect
set timeout 30

set ip [lindex $argv 0]
set port [lindex $argv 1]
set passphrase [lindex $argv 2]
set ssh_key_file [lindex $argv 3]

spawn /usr/bin/sudo -u sftp /usr/bin/ssh -ldiag_user -i $ssh_key_file $ip -p $port -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no"
expect "passphrase for"
send "$passphrase\r"
expect "DEBUG> "
send "ls -l\r"
expect "DEBUG> "

Output when running script:

$ expect rundiag.expect 10.10.10.123 22 somePassword /opt/the_keyfile
spawn /usr/bin/sudo -u sftp /usr/bin/ssh -ldiag_user -i /opt/the_keyfile 10.10.10.123 -p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
Warning: Permanently added '10.10.10.123:22' (RSA) to the list of known hosts.
Enter passphrase for key '/opt/the_keyfile':
******

Welcome to diagnostics shell

DEBUG> l

The l echoed at the end is the first character of the ls -l command, but then the output just stops until the script times out.

I have tried some naive approaches like sending via send_tty or ending the command with \n instead of \r, but to no avail.

What should I change to be able to run commands after reaching the shell prompt?


Solution

  • It turned out that the SSH implementation on these IoT devices is quite severely flawed, as it in turn wraps an internal Telnet server for legacy reasons.

    Adding a 0.5 second sleep after connecting (while the device connects to itself on another port via Telnet) and a 0.1 second sleep between entering a command and sending \r did the trick.