Using the following shell code for remote telnet request:
{
sleep 5
echo admin
sleep 3
echo pass
sleep 3
echo ls
sleep 5
echo exit
} | telnet 172.16.1.1
I want to check if telnet connection was successful or not. Trying to use $?:
echo $?
But it always returns "1", even if telnet connection was OK.
Telnet is exceptionally difficult to script in this way, there is a high degree of asynchronicity with the time it takes to establish a connection and for your intended actions to complete. expect was created for exactly this kind of purpose. You launch a program, like telnet, then declare a series of expectations - eg, when 'username: ' is emitted from the program, and an action to trigger (eg: typing in the username).
There are also libraries or wrappers for expect in many languages:
python expect
ruby expect
perl expect
Here is an example that drives telnet to make an HTTP HEAD request:
set timeout 20
spawn telnet localhost 80
expect "Connected to "
send "HEAD / HTTP/1.0\r\n\r\n"
expect "HTTP 200 OK"
Given all of this, I feel I must point out that telnet is considered insecure. Ssh is a much better choice and supports better choices for authentication (eg: public/private key auth), restrictions for commands that can be run (via .ssh/authorized_keys). With ssh, and ssh-keys set up, your script reduces to a single shell command:
ssh user#hostname ls
ssh has great support for safe, secure remote command execution.
If I'm remembering correctly, this expect script does what you're doing above.
#!/usr/bin/expect
spawn telnet 172.16.1.1
expect username:
send admin
expect password:
send pass
expect "\$ "
send ls
expect "\$ "
send exit
Here's a useful link for getting started: http://oreilly.com/catalog/expect/chapter/ch03.html
Related
so im trying to make an if statement to tell me if an sftp connection was sucessfull or failed, and if its a sucess i want to run a piece of code that automates an sftp download that ive already made.
My problem is that this if statement executes this sftp connection, and then prompts me for a password and stalls the rest of the code.
i wanted to do something like this
if ( sftp -oPort=23 user#server )
then
expect <<-EOF
spawn sftp -oPort=23 user#server
.....
I want to know if its possible for me to make the if statement not execute the sftp connection and then not prompt me , maybe execute it on the background or something.
I would appreciate if someone could tell me if what im asking is possible, or propose a better solution to what im trying to do, thanks
You cannot not-execute a command and then react on the return value of the executed command (because this is what you really want to do: check if you can run sftp successful, and if so do a "proper" run; but you'll never know whether it can run successfull without running it).
So the main question is, what it is what you actually want to test.
If you want to test whether you can do a full sftp connection (with all the handshaking and what not), you could try running sftp in batch-mode (which is handily non-interactive).
E.g. the following runs an sftp session, only to terminate it immediately with a bye command:
if echo bye | sftp -b - -oPort=23 user#server ; then
echo "sftp succeeded"
fi
This will only succeed if the entire sftp session works (that is: you pass any key checks; you can authenticate, ...).
If the server asks you for a password, it will fail to authenticate (being non-interactive), and you won't enter the then body.
If you only want to check whether something is listening on port 23, you can use netcat for this:
if netcat -z server 23; then
echo "port:32 is open"
fi
This will succeed whenever it can successfully bind to port 23 on the server. It doesn't care whether there's an sftp daemon running, or (more likely) a telnet daemon.
You could also do some minimal test whether the remote server looks like an SSH/SFTP server: ssh servers usually greet you with a string indicating that they indeed speak ssh: something like "SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4".
With this information you can then run:
if echo QUIT | netcat server 23 | grep SSH; then
echo "found an ssh server"
fi
I have the following scenario:
I use netcat to connect to a host running telnet server on port 23, I log in using provided username and password, issue some commands, after which I need to do fairly complex analysis of the provided output. Naturally, expect comes to mind, with a script like this:
spawn nc host 23
send "user\r"
send "pass\r"
send "command\r"
expect EOF
then, it is executed with expect example.scr >output.log, so the output file can be parsed. The parser is 150+ lines of bash code that executes under 2 seconds, and makes a decision what command should be executed next. Thus, it replaces "command" with "command2", and executes the expect script again, like this:
sed -i '/send "command\r"/send "command2\r"/' example.scr
expect example.scr >output.log
Obviously, it is not needed to re-establish telnet connection and perform log in process all over again, just to issue a single telnet command after 2 seconds of processing. A conclusion can be made, that telnet session should be kept alive as a background process, so one could freely talk to it at any given time. Naturally, using named pipes comes to mind:
mkfifo in
mkfifo output.log
cat in | nc host 23 >output.log &
echo -e "user\npass\ncommand\n" >in
cat output.log
After the file is written to, EOF causes the named pipe to close, thus terminating the telnet session. I was thinking what kind of eternal process could be piped to netcat so it can be used as telnet relay to host. I came up with a very silly idea, but it works:
nc -k -l 666 | nc host 23 >output.log &
echo -e "user\npass\ncommand\n" | nc localhost 666
cat output.log
The netcat server is started with k(eep alive), listening on port 666, and any data stream is redirected to the netcat telnet client connected to the host, while the entire conversation is dumped to output.log. One can now echo telnet commands to nc localhost 666, and read the result from output.log.
One should keep in mind that the expect script can be easily modified to accommodate SSH and even serial console connection, just by spawning ssh or socat instead of netcat. I never liked expect because it forces a use of another scripting language within bash, requires tcl libraries, and needs to be compiled for the embedded platforms, while netcat is a part of busybox and readily available everywhere.
So, the question is - could this be done in a simpler way? I'd put my bet on having some sort of link between console and TCP socket. Any suggestions are appreciated.
How about using like a file descriptor?
exec 3<>/dev/tcp/host/port
while true; do
echo -e "user\npass\ncommand" >&3
read_response_generate_next_command <&3 >&3
# if no more commands, break;
done
exec 3>&-
I am trying to transfer a file from one server to a remote server with the help of a TCL script.
But my script stops after the message "200 Port set okay" and continues to rum from the below telnet session.
I have checked the destination location, my file is not transferred.
Please suggest what can I do or where I am wrong
#!/usr/bin/tclsh
#!/usr/bin/expect
package require Expect
set p "mm155_005.006.010.200_bt.fw"
#**************************************************************\
FILE TRANSFER TO REMOTE SERVER \
***************************************************************
spawn ftp 10.87.121.26
expect "User (10.87.121.26:(none)):"
send "user\r"
expect "Password:"
send "pswd\r"
expect "ftp>"
send "cd FW\r"
expect "ftp>"
send "ha\r"
expect "ftp>"
send "bi\r"
expect "ftp>"
send "mput \"$p\"\r"
expect "mput $p? "
send "yes\r"
expect "ftp>"
send "ls\r"
#**************************************************************\
RUNNING THE TRANSFERED FILE \
***************************************************************
spawn telnet 10.87.121.26
expect "Login: "
send "user\r"
expect "password: "
send "pswd\r"
expect "*? > "
send "cd FW\r"
expect "*? > "
send "burnboot 30 5.6(10.200)\r"
Output
spawn ftp 10.87.121.26
Connected to 10.87.121.26.
220 VxWorks FTP server (VxWorks VxWorks5.4.2) ready.
Name (10.87.121.26:vkumar): user
331 Password required
Password:
230 User logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd FW
250 Changed directory to "C:/FW"
ftp> ha
Hash mark printing on (1024 bytes/hash mark).
ftp> bi
200 Type set to I, binary mode
ftp> mput "mm155_005.006.010.200_bt.fw"
mput mm155_005.006.010.200_bt.fw? yes
200 Port set okay \ I am unable to see hash progress bar after this line
spawn telnet 10.87.121.26
Trying 10.87.121.26...
Connected to 10.87.121.26.
Escape character is '^]'.
Login: user
password:
node84.7.PXM.a > cd FW
node84.7.PXM.a > bash-2.05b$
Instead of rolling your own solution in Expect (I also did this about 9 years ago), use the FTP module from tcllib -- it's already battle-hardened.
http://tcllib.sourceforge.net/doc/ftp.html
The script as reported is unlikely to produce exactly that output; there is nothing from the ls done after the mput. However, if the mput is hanging the most likely problem is that there is a firewall issue; FTP uses multiple sockets to do file transfers (which is why FTP is such a pain when it comes to overall firewall management). In particular, it has a command channel (the socket which you communicate with the FTP server over) and a separate data channel per file (and also with the output of some remote commands, such as ls); that's what that Port set okay is about. This is not firewall-friendly, and it's easy to misconfigure firewalls in this area (especially when there is NAT also in place).
You might (i.e., try this first) want to use passive mode instead, as that reduces the complexity at the firewall level. Try issuing a passive before the mput (just as you currently issue a binary).
Here's a bash script I wrote with a similar function;
You should be able to adapt it to your needs.
Adding a few lines to SSH in and run the script should be quite trivial.
As a side note; why are you using TCL for this?
#!/bin/bash
fileName=`ls /home/user/downloads -t1 | head -n1`
latestFile="/home/user/downloads/$fileName"
echo $latestFile
hostname="HOSTNAME"
username="USER"
password="PASS"
ftp -inv $hostname << EOF
quote USER $username
quote PASS $password
cd transfer/jirabackup
binary
put $latestFile $fileName
quit
This is the first time I am writing a shell script. I tried to do as much research as I can to avoid dumb/repetitive question. Please excuse if its repeat/dumb question.
I have a shell script which connects to remote linux machine and runs scripts there. I am using 'expect' to spawn a ssh connection and to issue commands to trigger the job. However, I am having issues while closing the connection after completing the job.
This is my script:
set prompt "(%|#|\\$|%\]) $"
expect -c 'spawn ssh $UN#$STAGE ;
expect password ; send "$PASS \n";
expect -regexp "$PROMPT"; send "./settings.$UN.sh > settings_log.txt \n";
interact'
This script successfully runs the script file for me ($UN and $STAGE parameters are input to the script. I omitted that here for simplicity). However, this leaves me with an open connection.
I tried to close the connection after running the script by using following instead of above
expect -c 'spawn ssh $UN#$STAGE ;
expect password ; send "$PASS \n";
expect -regexp "$PROMPT"; send "./settings.$UN.sh > settings_log.txt \n";
expect -regexp "$PROMPT"; send "exit \n"'
This does close the connection but I noticed that my script file did not run at all. Also the settings_log.txt is not generated at all.
Does this mean, that exit command is aborting the process before its completion? I tried using 'sleep' before exit but it did not help. Is there a better suggested way to terminate the connection when using expect?
Any help is appreciated.
with expect, you terminate your send commands with \r not \n, so
expect -c 'spawn ssh $UN#$STAGE
expect password
send "$PASS\r"
expect -regexp "$PROMPT"
send "./settings.$UN.sh > settings_log.txt\r"
expect -regexp "$PROMPT"
send "exit\r"
expect eof'
Note you can execute remote shell commands and copy files using ssh and scp, directly, without using expect.
For example,
scp ./settings.$UN.sh $UN#$STAGE:settings_log.txt
ssh $UN#$STAGE whatever-you-need-to-execute
The connection will close as soon as soon as whatever-you-need-to-execute completes.
Your outer script seems to be written in csh and sets a variable named "prompt", but your expect script is using a variable called "PROMPT". Try making the two variable names match case.
This question already has answers here:
Using expect to pass a password to ssh
(6 answers)
Closed 5 years ago.
So I wanted to automate my SSH logins. The host I'm with doesn't allow key authentication on this server, so I had to be more inventive.
I don't know much about shell scripting, but some research showed me the command 'expect' and some scripts using it for exactly this purpose. I set up a script and ran it, it worked perfectly to login.
#!/usr/bin/env expect -f
set password "my_password"
match_max 1000
spawn ssh -p 2222 "my_username"#11.22.11.22
expect "*?assword:*"
send -- "$password\r"
send -- "\r"
expect eof
Initially, it runs as it should.
Last login: Wed May 12 21:07:52 on ttys002
esther:~ user$ expect expect-test.exp
spawn ssh -p 2222 my_username#11.22.11.22
my_username#11.22.11.22's password:
Last login: Wed May 12 15:44:43 2010 from 20.10.20.10
-jailshell-3.2$
But that's where the success ends.
Commands do not work, but hitting enter just makes a new line.
Arrow keys and other non-alphanumeric keys produce symbols like '^[[C', '^[[A', '^[OQ' etc.[1]
No other prompt appears except the two initially created by the expect script.
Any ignored commands will be executed by my local shell once expect times out.
An example:
-jailshell-3.2$ whoami
ls
pwd
hostname
(...time passes, expect times out...)
esther:~ user$ whoami
user
esther:~ ciaran$ ls
Books Documents Movies Public
Code Downloads Music Sites
Desktop Library Pictures expect-test.exp
esther:~ ciaran$ pwd
/Users/ciaran
esther:~ ciaran$ hostname
esther.local
As I said, I have no shell scripting experience, but I think it's being caused because I'm still "inside of" expect, but not "inside of" SSH. Is there any way to terminate expect once I've logged in, and have it hand over the SSH session to me?
I've tried commands like 'close' and 'exit', after " send -- "\r" ". Yeah, they do what I want and expect dies, but it vindictively takes the SSH session down with it, leaving me back where I started. What I really need is for expect to do its job and terminate, leaving the SSH session back in my hands as if I did it manually.
All help is appreciated, thanks.
[1] I know there's a name for this, but I don't know what it is. And this is one of those frightening things which can't be googled, because the punctuation characters are ignored. As a side question, what's the story here?
I think your problem has been solved here before:
Using expect to pass a password to ssh
The command you're looking for is interact. It hands the control over to you/your keyboard.
I've used a similar script to autologin.
I used "interact" and I removed "expect eof". By doing this, I can get the screen back so that I can enter commands by hand.
expect "?assword: "
send -- "$password\r"
expect "$"
interact
putting it all together, log you in and leave you on the command line exactly as though you typed it manually
#!/usr/bin/expect -f
set ip "127.001.001.001"
set password "xxyykkx"
spawn ssh $ip -l root
expect "?assword:"
send "$password\r"
interact