135

I am in the process of creating a bash script that would log into the remote machines and create private and public keys.

My problem is that the remote machines are not very reliable, and they are not always up. I need a bash script that would check if the SSH connection is up. Before actually creating the keys for future use.

3
  • 3
    Typically, one runs ssh-keygen to generate a keypair on the local machine, then ssh-copy-id to copy the public key to remote machines. It seems that you are doing things differently. Why, what is your goal? Commented Sep 10, 2009 at 19:43
  • 1
    Since you’re obviously changing how the remote machines establish connections, consider deploying mosh. mosh.mit.edu It is intended to supplement SSH on unstable connections. I have very good experiences with it. Commented Aug 13, 2013 at 11:08
  • @ephemient I know it's a bit late, but it seems pretty straightforward that they key was not for the local machine or not for the local user. Commented Apr 27, 2019 at 13:10

14 Answers 14

237

You can check this with the return-value ssh gives you:

$ ssh -q user@downhost exit
$ echo $?
255

$ ssh -q user@uphost exit
$ echo $?
0

EDIT: Another approach would be to use nmap (you won't need to have keys or login-stuff):

$ a=`nmap uphost -PN -p ssh | grep open`
$ b=`nmap downhost -PN -p ssh | grep open`

$ echo $a
22/tcp open ssh
$ echo $b
(empty string)

But you'll have to grep the message (nmap does not use the return-value to show if a port was filtered, closed or open).

EDIT2:

If you're interested in the actual state of the ssh-port, you can substitute grep open with egrep 'open|closed|filtered':

$ nmap host -PN -p ssh | egrep 'open|closed|filtered'

Just to be complete.

Sign up to request clarification or add additional context in comments.

10 Comments

To be complete, can u indicate which return code means success and which means failure to SSH?
Wondering what if the SSH attempt just hangs there?
Great answer! However, you do not mention that attempting to ssh into a down host fails only after a timeout of e.g. 60 seconds - which might be prohibitive for some usages. Also, if a hostname if defined in ~/.ssh/config, the first ssh approach works while the second nmap way fails with Failed to resolve "<hostname>".
no explanation at all about the commands... or what you are actually doing.. what is $? ? etc
@ssc you can add the -o option to limit the timeout duration. The following example reduces it to 5 seconds: ssh -o ConnectTimeout=5 -q user@downhost exit
|
35

You can use something like this

$(ssh -o BatchMode=yes -o ConnectTimeout=5 user@host echo ok 2>&1)

This will output "ok" if ssh connection is ok

2 Comments

This will fail if a password is required and incorrectly not output ok, despite the remote being connectable.
Good answer but you should remove the BatchMode option in order to make it work even on systems that require a password.
23
ssh -q -o "BatchMode=yes" -i /home/sicmapp/.ssh/id_rsa <ID>@<Servername>.<domain> "echo 2>&1" && echo $host SSH_OK || echo $host SSH_NOK

1 Comment

One line output: (ssh -q -o "BatchMode=yes" -o "ConnectTimeout=3" [email protected] "echo 2>&1" && echo SSH_OK || echo SSH_NOK) | tail -n1
22

Complementing the response of @Adrià Cidre you can do:

status=$(ssh -o BatchMode=yes -o ConnectTimeout=5 user@host echo ok 2>&1)

if [[ $status == ok ]] ; then
  echo auth ok, do something
elif [[ $status == "Permission denied"* ]] ; then
  echo no_auth
else
  echo other_error
fi

Comments

10

Below ssh command should have an exit code of 0 on a successful connection and a non-zero value otherwise.

ssh -q -o BatchMode=yes [email protected] exit

if [ $? != "0" ]; then
    echo "Connection failed"
fi

1 Comment

Great! I recomment also adding -o ConnectTimeout=5, for faster exit in cases where the destination port is filtered.
7

Try:

echo quit | telnet IP 22 2>/dev/null | grep Connected

1 Comment

A problem of this approach is it does not recognize the hosts defined in ssh_config (i.e /etc/ssh/config or ~/.ssh/config)
4

Following @user156676, to check a range of ips:

#!/bin/sh
IP='192.168.0.'
PWD='your_password'
USR='your_usr'

for i in $(seq 229 255);do
    sshpass -p $PWD ssh -q -o ConnectTimeout=3 ${USR}@${IP}${i} exit
    let ret=$?
    if [ $ret -eq 5 ]; then
        echo $IP$i "Refused!"  $ret
    elif [ $ret -eq 255 ] ; then
        echo $IP$i "Server Down!" $ret
    elif [ $ret -eq 0 ] ; then
        echo $IP$i "Connnected!" $ret
    else
        echo $IP$i "Unknown return code!" $ret
    fi  
done

Comments

2

Just in case someone only wishes to check if port 22 is open on a remote machine, this simple netcat command is useful. I used it because nmap and telnet were not available for me. Moreover, my ssh configuration uses keyboard password auth.

It is a variant of the solution proposed by GUESSWHOz.

nc -q 0 -w 1 "${remote_ip}" 22 < /dev/null &> /dev/null && echo "Port is reachable" || echo "Port is unreachable"

-q 0 means leave as soon as idle.

-w 1 wait for connection for 1second.

Comments

1

To connect to a server with multiple interfaces

ssh -o ConnectTimeout=1 -q [email protected];[ $? = 1 ] || ssh -o ConnectTimeout=1 -q [email protected]

Comments

1

https://onpyth.blogspot.com/2019/08/check-ping-connectivity-to-multiple-host.html

Above link is to create Python script for checking connectivity. You can use similar method and use:

ping -w 1 -c 1 "IP Address" 

Command to create bash script.

2 Comments

This will only ping the remote IP. Does not guarantee if ssh connection is possible.
Thanks for pointing that out, here's the code for ssh xlinu.blogspot.com/2019/09/… export user="username" export pass="password" export i="hostname" export SSHPASS=$pass sshpass -e ssh $user@$i -q "echo $i is Accessible"
0

If you would like to check a remote folder exists, or any other file-test really:

if [ -n "$(ssh "${user}@${server}" [ -d "$folder" ] && echo 1; exit)" ]; then
    # exists
else
    # doesn't exist
fi

Do not forget the quotes in "$(ssh ...)".

1 Comment

This does not answer the question. The OP wants to check whether SSH connection can be established not checking a file in a remote ssh location.
0

Example Using BASH 4+ script:

# -- ip/host and res which is result of nmap (note must have nmap installed)
ip="192.168.0.1"
res=$(nmap ${ip} -PN -p ssh | grep open)

# -- if result contains open, we can reach ssh else assume failure) --
if [[ "${res}" =~ "open" ]] ;then
    echo "It's Open! Let's SSH to it.."
else
    echo "The host ${ip} is not accessible!"
fi

Comments

0

I wrote this script to check both netcat and SSH connectivity to all hosts in my servers /etc/hosts

reads /etc/hosts line by line and then tries netcat port 22, and then ssh as "sshuttle" user

quick way to check network sanity

script uses a "sshuttle" user, this is an account that has pub/priv keys on all my hosts and can ssh anywhere (non root account), we use this acct to spin up sshuttle VPN tunnels, but you can add any account that has SSH access to servers

https://gist.github.com/perfecto25/8687d563716ba4923c77162be724beda

output,

./conncheck.sh


netcat is installed, proceeding..
--------------------------------------
tm-us1 (127.0.0.1): ssh OK | nc OK
--------------------------------------
localhost (127.0.0.1): ssh OK | nc OK
--------------------------------------
atlas (192.168.142.21): ssh ERROR | nc OK
--------------------------------------
hydra (192.168.142.22): ssh OK | nc OK
--------------------------------------
nemesis (192.168.140.23): ssh OK | nc OK
--------------------------------------
vulcan (192.168.140.24): ssh OK | nc OK
--------------------------------------
athena (192.168.140.27): ssh OK | nc OK
--------------------------------------
nas1 (192.168.100.101): ssh ERROR | nc OK
--------------------------------------
tm-dev (192.10.23.71): ssh ERROR | nc ERROR
--------------------------------------
WARNING: Your password has expired.
Password change required but no TTY available.
infra01 (192.10.23.186): ssh ERROR | nc OK
--------------------------------------
ns-us1 (192.10.23.252): ssh ERROR | nc OK
--------------------------------------
ns-us2 (192.10.23.182): ssh ERROR | nc OK
--------------------------------------
proxy-us1 (192.10.23.120): ssh OK | nc OK
--------------------------------------
simtm-us1 (192.10.23.236): ssh OK | nc OK
--------------------------------------
tm-us1 (192.10.23.104): ssh OK | nc OK
--------------------------------------
tm-us2 (192.10.23.215): ssh OK | nc OK
--------------------------------------
tm-dev (192.10.23.77): ssh OK | nc OK
--------------------------------------
WARNING: Your password has expired.
Password change required but no TTY available.
tm-uat (192.10.23.225): ssh ERROR | nc OK
--------------------------------------
vpn-us1 (192.10.23.193): ssh OK | nc OK
--------------------------------------

1 Comment

Please provide the script in your answer instead of (or in addition to) a link to it.
-7

I feel like you're trying to solve the wrong problem here. Shouldn't you be trying to make the ssh daemons more stable? Try running something like monit, which will check to see if the daemon is running and restart it if it isn't (giving you time to find the root problem behind sshd shutting down on you). Or is the network service troublesome? Try looking at man ifup. Does the Whole Damn Thing just like to shut down on you? Well, that's a bigger problem ... try looking at your logs (start with syslog) to find hardware failures or services that are shutting your boxen down (maybe a temperature monitor?).

Making your scripts fault tolerant is great, but you might also want to make your boxen fault tolerant.

1 Comment

Sam: there are valid use cases to have the script checking it. E.g (like me): I have a cron job running on my machine to backup my data via rsync to my home nas. Now I'm outside or even disconnected quite often and need to reschedule if the connection wasn't available. My boxen runs quite well, but as the saying goes: it is always the cable (a.k.a network)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.