ping script - host down vs host not on network - shell

I have the following script where I am trying to differentiate between a server that is down and a server that is no longer on the network.
If I use the ping command on the command line on a server that is just down and echo the $? I get a 1 as expected.
If I use the ping command on the command line on a server that is no longer on the network and echo the $? I get a 2 as expected. I can't seem to capture this behavior in my script. On the script below, the server that is no longer on the network does not appear at all in the badhosts output file. I am using the dev null on the ping line as I don't want to get the host unknown lines on the output which will skew the results.
Thanks in advance for any assistance.
#!/bin/ksh
# Take a list of hostnames and ping them; write any failures
#set -x
for x in `cat hosts`
do
ping -q -c 1 $x > /dev/null 2> /dev/null
if [ "$?" -eq 1 ];then
echo $x is on network but down >> badhosts
elif [ "$?" -eq 2 ];then
echo $x is not on the network >> badhosts
fi
done

I modified my script at the suggestion of Raman as follows and this works.
Thanks Raman !!
#!/bin/ksh
# Take a list of hostnames and ping them; write any failures
set -x
for x in `cat hosts`
do
ping -c 1 $x > /dev/null 2> /dev/null
pingerr=$?
if [ $pingerr -eq 1 ]; then
echo $x is on network but down >> badhosts
fi
if [ $pingerr -eq 2 ]; then
echo $x is not on the network >> badhosts
fi
done

Related

Checking whether specific website is up in the terminal?

Is there an easy way to check Internet connectivity from console? I am trying to play around in a shell script. One idea I seem is to wget --spider http://www.google.com/ and check the HTTP response code to interpret if the Internet connection is working fine.
This is what I am trying:
#!/bin/bash
# Sending the output of the wget in a variable and not what wget fetches
RESULT=`wget --spider http://google.com 2>&1`
FLAG=0
# Traverse the string considering it as an array of words
for x in $RESULT; do
if [ "$x" = '200' ]; then
FLAG=1 # This means all good
fi
done
Is there any way to accomplish this?
You can do it with ping or curl commands. Check man for more.
I am using this for myself and kinda works for me! It checks the connection from a reliable website like google and if it gets 200 status as the response, you probably have internet.
if curl -s --head --request GET www.google.com | grep "200 OK" > /dev/null ; then
echo "Internet is present"
else
echo "Internet isn't present"
fi
On one line, thanks #PS
if ping -c1 8.8.8.8 &>/dev/null ;then echo Working ;else echo Down ;fi
An option that does not use the internet to see if it is available is to check for a default route in your routing tables. The routing daemon will remove your default route when the internet is not available and add it back when it is.
netstat -nrf inet | grep -q ^default && \
echo internet is up || \
echo internet is down
To check if a website is up, you can use netcat to see if it is listening on port 80. This helps with sites that refuse head requests with '405 Method Not Allowed'.
nc -zw2 www.example.com 80 &>/dev/null && \
echo website is up || \
echo website is down
Please try this code.
#!/bin/bash
wget -q --spider http://google.com
if [ $? -eq 0 ]; then
echo "Internet connection is OK"
else
echo "Internet connection is FAILED"
fi
A bit more compact variant of #carlos-abraham answer. You can have curl to output just the http response code and make a decision with it
# 200 if everything is ok
http_code=$(curl -s --head -m 5 -w %{http_code} --output /dev/null www.google.com)
if [ "$http_code" -eq 200 ]; then
echo "success"
else
# write error to stderr
echo "http request failed: $http_code" >&2
exit 1
fi
-m 5: wait 5 seconds for the whole operation
--output /dev/null: suppress html site response
-w %{http_code}: write to stdout the http response code.
A bit more elaborated script to check connectivity and http response
#url="mmm.elgoog.moc"
url="www.google.com"
max_wait=5
(ping -w $max_wait -q -c 1 "$url" > /dev/null 2>&1 )
response_code=$?
if [ "$response_code" -eq 0 ]; then
# 200 if everything is ok
response_code=$(curl -s --head -m $max_wait -w %{http_code} --output /dev/null "$url")
fi
case "$response_code" in
1)
echo "Connectivity failed. Host down?" >&2
exit $response_code
;;
2)
echo "Unknown host or other problem. DNS problem?" >&2
exit $response_code
;;
200)
echo "success"
exit 0
;;
*)
echo "Failed to get a response: $response_code" >&2
exit 1
esac

How to check connection to a list of servers in bash?

Im trying to check connections for a list of servers. I want to loop through the list, check if a connection works and if yes, do some stuff, if not, echo out a problem message.
My problem is:
the script stops at the first node without echoing the $?.
So, whats wrong with my for-loop?
These vars are included from a config file:
$nodes is a list of server IPs like 1.1.1.1,2.2.2.2,10.10.10.10
$user is one string
for node in $(echo $nodes | sed "s/,/ /g")
do
echo "Checking Node: $node"
ssh -q -o ConnectTimeout=3 $user#$node echo ok
echo $?
if [[ $? != 0 ]]
then
echo "Problem in logging into $node"
else
# do some stuff here
fi
done
EDIT #1:
for node in $(echo $nodes | sed "s/,/ /g")
do
echo "Checking Node: $node"
ssh -q -t -o ConnectTimeout=3 $user#$node "echo ok"
retcode=$?
echo $retcode
if [[ "$retcode" -ne 0 ]]
then
echo "Problem in logging into $node"
else
echo "OK"
fi
done
It is because ssh first asks you to validate The authority of the host and If you accept the authority it will ask for password. That is why your command does not return to shell and waits for input.
If your intention is just validating ssh connection, then you may consider to use
telnet <your_host> <port> < /dev/null
But if your intend is to run some commands you need a trust relationship between hosts. In that case you can use:
Execute this commands:
ssh-keygen -t rsa
then
ssh-copy-id -i root#ip_address
Now you can connect with
ssh <user>#<host>
Furher information
You can add -tto make virtual terminal and add quotes on command:
ssh -q -t -o ConnectTimeout=3 ${user}#${node} "echo ok"
Also use -ne instead of != which is for compare strings
if [[ "$?" -ne 0 ]]
Also echo $? mess the return code. You should use something like:
ssh -q -t -o ConnectTimeout=3 ${user}#${node} "echo ok"
retcode=$?
echo $retcode
if [[ "$retcode" -ne 0 ]]
You can rewrite ssh command like this to avoid problems with ssh host keys
ssh -q -t -o StrictHostKeyChecking=no -o ConnectTimeout=3 ${user}#${node} "echo ok"

Bash script with netcat operations on different server and port

I am a bit lost. I have created a script which starts by retrieving data from a CSV file. Each line contains an IP address and a few ports to test. The goal is to verify that it is possible to connect to each server (under the given IP) on specifics ports. In order to verify, the following code is used:
nc -w 3 -v $ipValeur >> retour.txt 2>&1
Nevertheless, it doesn't work and it returns Connection Timed out. It is strange. In fact, if I launch a telnet command from a terminal, it works. Nevertheless, the goal is to check if a server can be connected to a lot of others. So, if telnet is used, it will be very long (one or two days ?)...
So, I am looking for a way which permits to automatically verify the access from one server to thirty others on a few ports. You can find the code which is actually used at How to continue next iteration when an error occurs in Bash.
Thank you for your help.
Solution
#!/bin/bash
INPUT_FILE=$1
while IFS='' read -r line || [ -n "$line" ]; do
IFS=';' read -ra cvsline <<<${line}
HOSTNAME=${cvsline[0]}
ports=("${cvsline[#]:1}")
for port in ${ports[*]}; do
echo -n "Verification ${HOSTNAME}:${port}..."
echo 'QUIT' | nc -w 3 -v "${HOSTNAME}" "${port}" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "OK"
else
echo "KO"
fi
done
done < $INPUT_FILE
Vinz
The answer may be, that in command: nc -w 3 -v $ipValeur >> retour.txt 2>&1 you not passed port number, and was used default one all the times
I not really able to understand your source code, so i have written my own based on description:
#!/bin/bash
INPUT_FILE=$1
while IFS='' read -r line || [ -n "$line" ]; do
IFS=';' read -ra cvsline <<<${line}
HOSTNAME=${cvsline[0]}
ports=("${cvsline[#]:1}")
for port in ${ports[*]}; do
echo -n "Cheking ${HOSTNAME}:${port}..."
nc -zw 3 "${HOSTNAME}" "${port}" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "connected"
else
echo "not connected"
fi
done
done < $INPUT_FILE
Usage:
./script hostlist.cvs
Where hostlist.cvs:
127.0.0.1;80;90;100;
127.0.0.2;80;88;21;
10.255.0.1;80;443;
And output sample:
$ ./test.sh /tmp/1
Cheking 127.0.0.1:80...not connected
Cheking 127.0.0.1:90...not connected
Cheking 127.0.0.1:100...not connected
Cheking 127.0.0.2:80...not connected
Cheking 127.0.0.2:88...not connected
Cheking 127.0.0.2:21...not connected
Cheking 10.255.0.1:80...connected
Cheking 10.255.0.1:443...not connected

Convert bash script to Windows

I wrote the following script for Linux in order to detect drops in my network connection:
#!/bin/bash
echo "### RUNNING ###"
echo "### $(date) ###"
while true;do
now=$(date +"%T")
if [[ "$(ping -c 1 8.8.8.8 | grep '100.0% packet loss' )" != "" ]]; then
echo "!!! KO ($now)" >> "log_connectivity_$(date +"%F")"
else
echo "OK ($now)" >> "log_connectivity_$(date +"%F")"
fi
sleep 5s
done
What it does is, within a loop, to ping 8.8.8.8 once and, if packet is lost it prints KO and the time and, otherwise, it prints OK and the time.
I would like to translate this bash script into a Windows script, but I have no idea. I would be very grateful if you could help me with this.
Thanks in advance ;)

Ping Tool to check if server is online

Is this tool that I created from various SOF threads valid? Will it work? I want to have a ping test done to a server every minute. If it fails 5 times in a row it sends an email out. It then flushes and resets the script pretty much to check again.
#!/bin/bash
# ping checker tool
numOfFails=0
incrememnt=1
EMAILMESSAGE="/tmp/emailmessage.txt"
while true; do
if ! ping -c 1 google.com ; then #if ping exits nonzero...
numOfFails=$(($num + $increment))
else
numOfFails=0
fi
if ((numOfFails > 4)); then
numOfFails=0
echo "SAN is offline!" > $EMAILMESSAGE
mail -s "SAN offline" "test#test.com" < $EMAILMESSAGE
fi
sleep 60 #check again in one minute
done
Your code won't work at all, this is a revised version:
#!/bin/bash
# ping checker tool
FAILS=0
EMAIL_ADDRESS="example#example.com"
SERVER="192.168.1.1"
SLEEP=60
while true; do
ping -c 1 $SERVER >/dev/null 2>&1
if [ $? -ne 0 ] ; then #if ping exits nonzero...
FAILS=$[FAILS + 1]
else
FAILS=0
fi
if [ $FAILS -gt 4 ]; then
FAILS=0
echo "Server $SERVER is offline!" \
| mail -s "Server offline" "$EMAIL_ADDRESS"
fi
sleep $SLEEP #check again in SLEEP seconds
done
Change example#example.com and 192.168.1.1 for your email address and the IP address of the server you are testing. I recommend using and IP address instead of a hostname to prevent mixing name resolution errors with connection errors.
Please be advised that although this will work I would recommend running a slightly different script from cron instead of having it running continuously like you seem to want, when running from cron you would not need to monitor that the script is running since if it stops for some reason the monitoring of the server stops as well.
Something like this run from crontab every minute.
#!/bin/bash
# ping checker tool
TMP_FILE="/tmp/ping_checker_tool.tmp"
if [ -r $TMP_FILE ]; then
FAILS=`cat $TMP_FILE`
else
FAILS=0
fi
EMAIL_ADDRESS="example#example.com"
SERVER="192.168.1.1"
ping -c 1 $SERVER >/dev/null 2>&1
if [ $? -ne 0 ] ; then #if ping exits nonzero...
FAILS=$[FAILS + 1]
else
FAILS=0
fi
if [ $FAILS -gt 4 ]; then
FAILS=0
echo "Server $SERVER is offline!" \
| mail -s "Server offline" "$EMAIL_ADDRESS"
fi
echo $FAILS > $TMP_FILE
Consider using Pingdom. It provides this service for you.
One thing you have not considered is once your site goes down, you will continue to get email messages every minute, until the site is up again, or until you stop this script.
A good approach is to switch states from reporting when the site is down to reporting when the site is up, once you have detected that it is down. And then back again, once it is back up.
Essentially you one receive an email reporting 'site down', then another later on, hopefully, reporting 'site is up'.
Pingdom does this for you, very nicely.
I have been investigating how to do this so that I can activate/deactivate services depending on whether my phone is at home. I have come up with the following:
#!/bin/bash
HOST_TO_CHECK=<hostname>
if ping -qc 20 $HOST_TO_CHECK >/dev/null; then
echo "Host $HOST_TO_CHECK is up"
else
echo "Host $HOST_TO_CHECK is down"
fi
Replace <hostname> with the host you wish to check.
The script will ping the host 20 times.
The reason it does this is that my mobile doesn't always respond to pings immediately.
Obviously you can replace the echo commands with something to actually do something useful :-)
You can then schedule the script to check every 5 minutes by adding it to your crontab:
*/5 * * * * /opt/pingcheck.sh

Resources