Expect telnet automation fails without interact - telnet

The following Expect script works, but the interact at the end forces the user into an interactive session.
#!/usr/bin/expect -f
set timeout 10
spawn telnet sometelnetserver.com 10000
foreach line [split [read [open somefile.txt r]] "\n"] {
send "$line\n"
}
interact
However, removing the interact stops telnet from connecting. The script outputs
spawn telnet sometelnetserver.com 10000
and the remote never gets a connection.
Solution
Hackily solved by sending a proper quit command before interact so there's nothing to interact with.
#!/usr/bin/expect -f
spawn -noecho telnet sometelnetserver 10000
foreach line [split [read [open somefile.txt r]] "\n"] {
send -- "ed77e768-0a1f-4fda-98c0-c3e5af441f78 $line\r"
}
send \035
send quit\r
interact
This seems more than a little sketchy though, because it will still hang if the server doesn't respond.

Related

Using tcl/expect to prepare a tunnel

As part of a bigger plan (jumping through a bunch of hops and then create a port-tunnel to mongodb in a setup that PortForwarding is disabled) I attempted to create a tcl/expect script to verify if it is possible to relay a stream prepared by tcl/expect.
Here is my experiment:
# terminal 1 [listen to 2000]
nc -l 2000
# terminal 2 [listen to 200 then connect it to 2000 using expect]
socat tcp-l:200 system:'./nc-test.exp'
# terminal 3 [connect to 200]
nc localhost 200
and my tcl/expect simple script (nc-test.exp):
#!/usr/local/bin/expect
log_user 0
spawn nc localhost 2000
stty raw -echo
interact -o -nobuffer
Now the issue is everything I write in terminal 3 echos back to myself. Strangely this doesn't happen when I connect socat directly to nc localhost 2000 or when I directly execute tcl/expect script. Could you please help me figure
What is causing the unwanted echo?
Is my bigger plan feasible? (My main worry is keeping the stream raw)
The stty command in the expect script is acting on /dev/tty, which is probably the tty in terminal 2. However, spawn creates another pty to talk with the command it launches. That tty will inherit from the current tty, i.e. terminal 2, so will have echo on. It might be enough to simply move the stty raw -echo line to before the spawn, or more explicitly you can set the stty setting to be used by spawn by a command like
set stty_init "raw -echo"
before the spawn.

Expect script not working and terminal closes immediately

I don't know what's wrong with the script. I set up a new profile on Iterm terminal to run the script, but it never works and closes immediately. Here's the script:
#!/usr/bin/expect -f
set timeout 120
set secret mysecret
set username asdf
set host {123.456.789.010}
set password password123
log_user 0
spawn oathtool --totp --base32 $secret
expect -re \\d+
sleep 400
set otp $expect_out(0,string)
spawn ssh -2 $username#$host
expect "*assword:*"
send "$password\n"
expect "Enter Google Authenticator code:"
send "$otp\n"
interact
First, test you ssh connection with:
ssh -v <auser>#<apassword>
That will validate the SSH session works.
Make sure to not use ssh -T ..., since you might need a terminal for expect commands to work.
Second, add at least an echo at the beginning of the script, to see if it is called:
puts "Script running\r"
Third, see if a bash script, with part of it using expect as in here, would work better in this case

Tcl Expect fails spawning SSH to server but SSH from command line works

I have some code that I'm using to connect to a server and perform some commands. The code is as follows:
#!/usr/bin/expect
log_file ./log_std.log
proc setPassword {oldPass newPass} {
send -- "passwd\r"
expect "* Old password:"
send -- "$oldPass\r"
expect "* New password:"
send -- "$newPass\r"
expect "* new password again:"
send -- "$newPass\r"
}
set server [lindex $argv 0]
spawn /bin/ssh perfgen#$server
# Increase buffer size to support large text responses
match_max 100000
# Conditionally expects a prompt for host authenticity
expect {
"*The authenticity of host*" {
send -- "yes\r"
}
}
What I find very strange is that when I SSH from my command line the SSH command works no problem. However, when I SSH from the shell script I get the following error:
spawn /bin/ssh perfgen#192.168.80.132
ssh: Could not resolve hostname 192.168.80.132
: Name or service not known
The same script runs against 3 servers, but 2 of the 3 servers always fail. However, if I try logging into the servers manually do do the work all three servers pass.
Any idea what might be happening here? I'm completely stumped. This code was working up until about 2 weeks ago and according to the server administrator nothing has changed on the server-side config.
Trimming any whitespace seemed to solve the issue:
set serverTrimmed [string trim $server]

Using expect script to do an ssh from a remote machine

I am new to expect scripts and have a use case in which I need to do an ssh from a machine in which I have already done an ssh using expect script. This is my code snippet
#!/usr/bin/expect -f
set timeout 60
spawn ssh username#machine1.domain.com
expect "Password: "
send "Password\r"
send "\r" # This is successful. I am able to login successfully to the first machine
set timeout 60
spawn ssh username#machine2.domain.com #This fails
This takes a some amount of time and fails saying
ssh: connect to host machine2.domain.com port 22: Operation timed out. I understand that 22 is the default port on which ssh runs and I can manually override it by giving a -p option to ssh.
If I try to ssh independently without the expect script I get a prompt that asks me to enter (yes/no). From where is the correct port being picked up if I execute ssh directly without the expect script. If I do not need to enter the port number on shell why would it be needed to enter a port number if I am using an expect script.
That that point, you don't spawn a new ssh: spawn creates a new process on your local machine. You just send a command to the remote server
#!/usr/bin/expect -f
set timeout 60
spawn ssh username#machine1.domain.com
expect "Password: "
send "Password\r"
send "\r" # This is successful. I am able to login successfully to the first machine
# at this point, carry on scripting the first ssh session:
send "ssh username#machine2.domain.com\r"
expect ...

How can I account for connection failure using expect for ssh log-on automation?

I have a shell script that works fairly well for automating my ssh connections and for anything else that I would like to do via ssh. I'm very unsatisfied with the results, however, when host can't be found or if connection is refused. If the host cannot be found, upon timeout send prints my password onto the screen... no good. I've gotten around this by adding an infinite timeout < set timeout -1 >. When connection is refused; however, I get a message about how connection was refused and that there was an error sending, etc... and my password is printed as well. Is there a way to tell my script that if exact expect is not met then don't proceed to send, to just ctrl+c? The following is the relevant part of my shell script: (used in bash, by the way) Thanks in advance.
expect -c "
spawn ssh $USER#$HOST
expect -exact \"$USER#$HOST's password:\"
send \"$PASS\r\"
interact"
The answer is to expect the timeout keyword. If none of the patterns match, then the timeout condition occurs -- of course, you can't set the timeout value to -1: set it to a reasonable number of seconds.
Instead of cramming a large-ish script into the -c argument, put it into a file
#! /usr/local/bin/expect -f
set host [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
# or, foreach {host user password} $argv {break}
spawn ssh $user#$host
expect {
-re {password: $} {send "$password\r"}
timeout {error "ssh connection timed out!"}
}
interact