How to get telnet to send text and keep connected? - bash

for my work I need to connect to a lot of different servers every day: telnet ti the host, enter username, enter password - commence work.
Now I wanted to make life easier by automatically entering the username - I managed to do that, but telnet quits afterwards, that's obviously not what I wanted.
I work from a system with BASH and I can't install any programs there, so please don't give answers like "Use expect, that solves your problem easily..."
My tries led me to this:
function tn() { (echo "user"
sleep 1) | telnet $1 23
}
Calling the function with tn 123.45.67.89 connects to the server at 123.45.67.89, where the username is asked, which is entered automatically - great!
But then the password is asked, and instead of letting me enter it and begin my work, the connection is closed.
I really hope someone knows a solution for this!
Thanks in advance!

You might want to look at the expect command to script interactions with telnet:
#!/usr/bin/env bash
function tn() {
expect -f <<EOF
spawn telnet $1
expect "login"
send "${2}\r"
interact
EOF
}

telnetis designed for interactive usage. Use netcat, ncat, nc, socat or any other tool of this family.
Example:
( echo "user"; sleep 1) | ncat $1 23
But if you want to simulate interactive behavior, use socat and redirect stdin+stdout to a script:
Example:
socat TCP:$1:23 EXEC:my-shell.sh
In this case, a TCP connection for address $1 port 23 is established and stdin+stdout are redirected to stdout+stdin of the script. See man socat for details and more options.
my-shell.sh look for example like:
#!/bin/sh
read line
do_domething "$line"
printf "reply\n"
read line
do_domething "$line"
printf "reply\n"
btw, I have tested nothing (just written down)

Related

it is possible to use an if without executing its condition

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

If telnet output contains something execute action

I am trying to write a small script in bash. My target is that a Phone Call on my FritzBox will mute or pause my TV.
I get the information of a call via telnet (telnet fritz.box 1012) on my RaspberryPi and if there is coming a phone call in I get this output:
24.08.15 14:03:05;RING;0;017mobilephonenumber;49304myhomenumber;SIP0;
The only Part that is every time the same is the RING before the calling number. What I need is a script that checks the output of the telnet and if in the telnet output is a ring than execute an action in my case i just need to do a http request on an internal site or start another script.
This is what I have tried is this:
#!/bin/bash
#string='echo "My string"'
string=$(telnet –e p fritz.box 1012)
for reqsubstr in 'alt' 'RING';do
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'."
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
done
But I don`t get the output of my telnet session into the string. Anyone who can help me?
After you latest comment, and reading your question again, I think we can go for something simpler based on nc (netcat).
Let assume we create a bash script called action.sh
#!/bin/bash
while true;
do
read logline
for substr in 'alt' '\;RING\;'
do
if [[ "$logline" = *${substr}* ]]; then
echo "Got a match"
fi
done
done
Make the script executable, chmod +x action.sh, then start it with nc as follow:
nc -l fritz.box 1012 | ./action.sh
It will listen infinitely for incoming traffic from the box and should act as you want. I don't have your box obviously and I tested by starting it as nc -l 127.0.0.1 12000 and then provided input via telnet 127.0.0.1 12000, providing your RING sample. It seems to work.
$ nc -l 127.0.0.1 12000 | ./action.sh
Got a match
017mobilephonenumber
Got a match
017mobilephonenumber
Would this be more acceptable to you ? without expect (I am not an expect wizard anyway).
I hope this answer will help you more.
do you have access to expect? It is meant exactly for such kind of scenario. man expect is your friend, and I found a fair tutorial via google. If you google for modem expect you can find sample script for such scenario (I can find some for FritzBox too but not sure it's the same box as yours). I haven't used it in ages, though.
Here my short conclusion:
To see incomming calls on your FritzBox you can simply execute:
telnet fritz.box 1012
in your terminal.
The output should look like that:
24.08.15 14:03:05;RING;0;017mobilephonenumber;49304myhomenumber;SIP0;
I my case I want the execute an command the mutes my TV.
Here are the instructions how I controll my TV via Web/RaspberryPi (Philips Harmony Hub) if some one is interested.
To execute a command on an incomming call create a script called action.sh
#!/bin/bash
while true;
do
read logline
for substr in 'alt' '\;RING\;'
do
if [[ "$logline" = *${substr}* ]]; then
echo "Got a match"
#here you can put the command you want to execute on an incoming call
fi
done
done
After you create it make it executable using chmod +x action.sh
After that you can start the script using nc 192.168.1.1 1012 | action.sh
And that's how you execute a script on an incomming call!
Special thanks to tgo!!

BASH: keep connection alive

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>&-

How to get telnet execution result code from shell script?

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

Telnet inside a shell script

How can I run telnet inside a shell script and execute commands on the remote server?
I do not have expect installed on my solaris machine because of security reasons.
I also do not have the perl net::telnet module installed.
So with out using expect and perl how can I do it?
I tried the below thing but its not working.
#!/usr/bin/sh
telnet 172.16.69.116 <<!
user
password
ls
exit
!
When I execute it, this is what I am getting:
> cat tel.sh
telnet 172.16.69.116 <<EOF
xxxxxx
xxxxxxxxx
ls
exit
EOF
> tel.sh
Trying 172.16.69.116...
Connected to 172.16.69.116.
Escape character is '^]'.
Connection to 172.16.69.116 closed by foreign host.
>
Some of your commands might be discarded. You can achieve finer control with ordinary script constructs and then send required commands through a pipe with echo. Group the list of commands to make one "session":-
{
sleep 5
echo user
sleep 3
echo password
sleep 3
echo ls
sleep 5
echo exit
} | telnet 172.16.65.209
I had the same issue...however, at least in my environment it turned out being the SSL Certificate on the destination server was corrupted in some way and the server team took care of the issue.
Now, what I'm trying to do is to figure out how to get a script to run the exact same thing you're doing above except I want it to dump out the exact same scenario above into a file and then when it encounters a server in which it actually connects, I want it to provide the escape character (^]) and go on to the next server.

Resources