38

I have 5 Solaris servers present across different locations. Sometimes some of these servers are not reachable from my location due to various reasons (either because of network problems or the server itself goes down suddenly).

So I would like to write a Bash shell script to check wether they are reachable. What I have tried is:

ssh ipaddress "uname -a"

Password less authentication is set. If I don't get any any output I will generate a mail.

  1. Are there any otherways to check server reachability?
  2. Which one is the best way?
  3. Is what I have tried correct?
G. Sliepen
  • 7,637
  • 1
  • 15
  • 31
Balaswamy Vaddeman
  • 8,360
  • 3
  • 30
  • 40
  • 3
    You might want to check out Nagios. Gives you a lot more info and can be as verbose as you want it. – Jarmund Jan 20 '12 at 06:53
  • Your command is fine, but when it fails, there are many things which could be wrong. Start with this but add more checks over time to diagnose individual problems. A ping will not tell you whether the ssh daemon is up, but conversely, a failed ssh will not tell you whether the daemon died or the server's power adapter failed. – tripleee Jan 20 '12 at 08:19

7 Answers7

63

The most barebones check you can do is probably to use netcat to check for open ports.

to check for SSH (port 22) reachability, you can do

if nc -z $server 22 2>/dev/null; then
    echo "$server ✓"
else
    echo "$server ✗"
fi

from the manpage:

-z   Specifies that nc should just scan for listening daemons, without sending any data to them.

flying sheep
  • 8,475
  • 5
  • 56
  • 73
  • 1
    This is exactly what I was looking for. I am not sure why people rather to use ping that send packages instead only to check if the server is reachable. – Eduardo Reis Feb 24 '16 at 18:42
  • 1
    my answer is the newest one by ~3 years, but i hope more people will find it over time! – flying sheep Feb 25 '16 at 09:48
  • 3
    I recommend using -w as a timeout in scripts. Otherwise nc might hang forever in some situations. – Till Schäfer Dec 05 '16 at 17:16
  • 3
    On my macOS system, `nc -z $server` hangs indefinitely when server is not reachable, and adding `-w 2` makes no difference. I think the -w flag is for expiring an established connection, and doesn't have affect the -z flag. So using nc to detect an unreachable server doesn't seem helpful -- because it just hangs for a minute or so -- I want something that will give up after a couple seconds. – Dave Hein Jul 21 '18 at 20:58
  • 2
    Editing previous comment: On my macOS system, `nc -z $server 443` hangs indefinitely when server is not reachable, and adding `-w 2` makes no difference. That's with the built-in nc. I used Mac Ports to install gnetcat ... and 'gnetcat -z -w 2 $server 443' does time out after 2 seconds if the server is unreachable. – Dave Hein Jul 21 '18 at 22:14
  • mac Users should use nmap or something else (I commented on that in my post in this thread) – Mike Q Nov 18 '19 at 19:00
  • Why not something like `&>/dev/null ssh user@ip true && echo "up" || echo "down"`? So no need to install `nc` – alexis Apr 05 '22 at 14:17
35

Your ssh command will test for more than if the server is reachable - for it to work, the ssh server must be running, and everything must be right with authentication.

To just see if the servers are up, how about just a simple ping?

ping -c1 -W1 $ip_addr && echo 'server is up' || echo 'server is down'
coolaj86
  • 74,004
  • 20
  • 105
  • 125
gcbenison
  • 11,723
  • 4
  • 44
  • 82
17

You could use these options from the ping man page:

  • only send one packet ("c1"),
  • quiet mode ("q"),
  • (optional) Wait for 1 second for a response ("W1")

    ping -c1 -W1 -q $server

Ping returns different exit codes depending on the type of error. So, to test if it worked or not, just do "echo $?" to get the exit code. Like this:

ping 256.256.256.256 ; echo $?
# 68

ping -c 1 127.0.0.1 ; echo $?
# 0

ping -c 1 192.168.1.5 ; echo $?
# 2

Where

0 means host reachable
>0 means unreachable

So, to test this in a bash script, you could do something like:

ping -c1 -W1 -q $server &>/dev/null
status=$( echo $? )
if [[ $status == 0 ]] ; then
     #Connection success!
else
     #Connection failure
fi
Katie
  • 45,622
  • 19
  • 93
  • 125
8

Some more food for thought : Use nmap or nc, never ping.

Ping: Why should you not use ping ? (1) It is better to check the system and the port at the same time. (2) Ping is unreliable as icmp echo is blocked in many situations.

Nmap: This is very quick, very reliable but requires nmap to be installed Preferred method NMAP (ex host ip 127.0.0.1) :

nmap 127.0.0.1 -PN -p ssh | grep open

Nc: nc is usually installed already , however on some systems such as Mac OS X, the command hangs on unreachable systems. (see workaround)

nc -v -z -w 3 127.0.0.1 22 &> /dev/null && echo "Online" || echo "Offline"

Mac OSX Workaround :

bash -c '(sleep 3; kill $$) & exec nc -z 127.0.0.1 22' &> /dev/null
echo $?
0
bash -c '(sleep 3; kill $$) & exec nc -z 1.2.3.4 22' &> /dev/null
echo $?
143

(examples illustrate connecting to port 22 ssh over a good and bad host example, use the $? to determine if it reached the host with the sleep time of 3 seconds)

For Mac Users (mainly) etc, you can use the command in the script like so :

    # -- use NMAP, if not avail. go with nc --
    if command -v nmap | grep -iq nmap ; then
        nmap ${ip} -PN -p ${ssh_port} | grep -iq "open"
        res=$?
    elif command -v nc | grep -iq nc ; then
        # -- run command if fails to complete in 3 secs assume host unreachable --
        ( nc -z ${ip} ${ssh_port} ) & pid=$!
        ( sleep 3 && kill -HUP $pid ) 2>/dev/null & watcher=$!
        if wait $pid 2>/dev/null; then
            pkill -HUP -P $watcher
            wait $watcher
            # -- command finished (we have connection) --
            res=0
        else
            # -- command failed (no connection) --
            res=1
        fi
    else
        echo "Error: You must have NC or NMAP installed"
    fi

    if [[ ${res} -lt 1 ]] ;then
        success=1
        echo "testing  => $ip SUCCESS connection over port ${ssh_port}"
        break;
    else
        echo "testing => $ip FAILED connection over port ${ssh_port}"
    fi
Mike Q
  • 6,716
  • 5
  • 55
  • 62
  • Thanks for the answer, very useful. Do you know how to use nc command if behind a company proxy ? How would I nc to a server via proxy hob ? – DataBach Mar 15 '22 at 09:18
  • I just check and for me `nmap` is slower than a `ssh` connection to the server. So why is wrong to do something like `&>/dev/null ssh user@ip true && echo "up" || echo "down"` which is actually more close to the OP idea? – alexis Apr 05 '22 at 14:14
6

You can use ping -c4 $ip_address where $ip_address is the ip of your remote server and parse the output to capture the successful packets and/or failed packets and use mail -s to send the log via email.

Here is something to get you started and you can build on it.

ping -c4 www.google.com | awk '/---/,0'

This will give an output like this -

[jaypal:~/Temp] ping -c4 www.google.com | awk '/---/,0'
--- www.l.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 36.638/36.870/37.159/0.196 ms

I checked the Solaris man-page for ping. Output from ping on Solaris box is different. Also, on Linux you limit the packets by stating -c and number of packets. On Solaris you would have to do -

ping -s www.google.com 2 4

/usr/sbin/ping -s [-l | -U] [-adlLnrRv] [-A addr_family]
[-c traffic_class] [-g gateway [ -g gateway...]] [-
F flow_label] [-I interval] [-i interface] [-P tos] [-
p port] [-t ttl] host [data_size] [npackets]
                           ^           ^
                           |           |
---------------------------------------  

Unfortunately I don't have a solaris box handy to help you out with.

jaypal singh
  • 74,723
  • 23
  • 102
  • 147
5

You can use the nc -z -G 2 SERVER_HOST PORT approach with G instead of W. G being used for timeout before connection established , so if host is unreachable , you'll know faster

Ivo Varbanov
  • 59
  • 1
  • 3
  • this works but -G is -w and -z is not supported in my version of nc. I used `[[ $(nc -w 2 $HOST $PORT) ]] && echo $HOST reachable || echo $HOST unreachable` This for bash – DKebler Nov 08 '20 at 19:58
0

You can use below command,

ping -c1 -W1 ip_addr || echo 'server is down'  

you can't use $ip_addr as it will remove first number of your IP.

Amit
  • 13,134
  • 17
  • 77
  • 148
  • More accurate: `ping -c1 -W1 ip_addr || echo 'Firewall somewhere in between here and the server I need to contact is dropping ping packets so I do not know if the server is up or not'` – Andrew Henle Oct 01 '19 at 09:58