#!/bin/sh

# Simple shell script to check whether chennels to outside world are up.
# Licence is current GNU GPL.
#(c) Light Olli <olli@digger.org.ru>

# timeout between ping's.
pingtimeout=1

# named pid
namedpid=/chroot/named/var/run/named.pid

# timeout between ping's.
pingtimeout=1

# popular russsian internet HOSTs that do not deny or reject ICMP echo_requests.
r1=www.mail.ru
r2=www.rambler.ru
r3=ns.msu.ru

# foreign internet hosts (same restrictions).
f1=www.yahoo.com
f2=www.gov.com
f3=www.dataforce.com

# external hosts we use to check DNS functionality. Beware, that if addresses
# will ever change we'll get wrong results. These also should be from diffrent
# domains & ISPs. & also these should be mashines w/ common function like DNS,
# or web - these, most chances, won't travel. :)
#-
h1s=ns.ptt.ru
h1n=195.34.0.1
#-
h2s=ns.msu.ru
h2n=193.232.112.1
#-
h3s=ns.tsr.ru
h3n=213.135.67.1


# internal host we use to check local DNS functionality (1 of our IPs)
# these MUST be ABSENT from /etc/hosts.
h4s=gw.siora.ru
h4n=195.209.37.129

# our default gateways
gw1=195.209.37.25
gw2=212.38.105.1

#### output modifiers.
# enable/disable debugging.
debug=0
# whether we wanna see output from ping & other utils.
silence=1
# wether we wanna see human readable output generated by this script
verbose=0

# paths for utils
bc=/usr/bin/bc
ping=/bin/ping

# null device
null=/dev/null

# returns 0 on all OK, else returns 1 .
function check_hosts_reachability ()
{
 local funcdebug ; funcdebug=0; local result; local summ; summ=0; local retval;
 retval=1;
 # russian internet reachability check.
 if [ $verbose = "1" ]; then
	echo -e "\t\tStarting russian internet reachability check..";
 fi
 for HOST in $r1 $r2 $r3; do
  $ping -i $pingtimeout -c 3 -I 212.38.105.2 $HOST 1>$null 2>$null 3>$null;
  result=$?; summ=`echo "$summ + $result" | $bc -l`;
 done
 [ "$funcdebug" = "1" ] && echo "\$result=$result";
 test "$result" -gt "2";
 testvar=$?;
 [ "$funcdebug" = "1" ] && echo "\$testvar=$testvar";
 if [ "$testvar" = "0" ]; then 
    send_alert 6;
  else
  [ "$verbose" = "1" ] && echo -e \
  "\t\tThe russian segment of the internet seem to be OK.\n";
  retval=0;
 fi
 # foreign internet reachability check.
 if [ $verbose = "1" ]; then
	echo -e "\t\tStarting foreign internet reachability check..";
 fi
 summ=0;
 for HOST in $f1 $f2 $f3; do
  $ping -i $pingtimeout -c 3 -I 212.38.105.2 $HOST 1>$null 2>$null 3>$null;
  result=$?; summ=`echo "$summ + $result" | $bc -l`;
 done
 [ "$funcdebug" = "1" ] && echo "\$result=$result";
 test "$result" -gt "2";
 testvar=$?;
 [ "$funcdebug" = "1" ] && echo "\$testvar=$testvar";
 if [ "$testvar" = "0" ]; then 
    send_alert 5;
  else
  [ "$verbose" = "1" ] && echo -e \
  "\t\tThe foreign segment of the internet seem to be OK.\n";
  retval=0;
 fi
return $retval;
}

# returns 0 on all OK, else 1. Will lie if check-host is in /etc/hosts.
function check_does_dns_runs ()
{
 local funcdebug ; funcdebug=0; local testvar; local retval; local fretval;
 fretval=1;
 # named existence in process list check.
 kill -0 `cat $namedpid`
 retval=$?
 if [ "$retval" = "0" ]; then
   if [ $verbose = "1" ]; then
        echo -e "\t\tNamed is found in process list.";
	fretval=0;
   fi
  else
    send_alert 3;
   /etc/rc.d/init.d/named restart
 fi
 # just check does it really functioning on local names.
 # will lie if host is in /etc/hosts.
 summ=0;
 for HOST in $h4s $h4n; do
  $ping -i $pingtimeout -c 3 -I 212.38.105.2 $HOST 1>$null 2>$null 3>$null;
  result=$?; summ=`echo "$summ + $result" | $bc -l`;
  [ "$funcdebug" = "1" ] && echo "summ:$summ";
 done
 # if $result > 2 
 [ "$funcdebug" = "1" ] && echo "\$result=$result";
 test "$result" -gt "2";
 testvar=$?;
 [ "$funcdebug" = "1" ] && echo "\$testvar=$testvar";
 if [ "$testvar" = "0" ]; then 
  send_alert 4;
  else
  [ "$verbose" = "1" ] && echo -e \
  "\n\t\tThe local DNS seem to be OK.\n";
  fretval=0;
 fi
 
}

# returns 0 on all OK, else returns 1
function check_remote_dns ()
{ local funcdebug ; funcdebug=0; summ=0; local fretval; fretval=1;
 summ=0;
 for HOST in $h1s $h1n $h2s $h2n $h3s $h3n; do
  $ping -i $pingtimeout -c 3 -I 212.38.105.2 $HOST 1>$null 2>$null 3>$null;
  result=$?; summ=`echo "$summ + $result" | $bc -l`;
  [ "$funcdebug" = "1" ] && echo "summ:$summ";
 done
 # if $result > 2 
 [ "$funcdebug" = "1" ] && echo "\$result=$result";
 test "$result" -gt "2";
 testvar=$?;
 [ "$funcdebug" = "1" ] && echo "\$testvar=$testvar";
 if [ "$testvar" = "0" ]; then 
   send_alert 7;
   else
    [ "$verbose" = "1" ] && echo -e "\t\tRemote DNS seem to be reachable."
    fretval=0;
 fi
}

# done (some 2do are still awaiting their time though)
function check_gateways ()
{
 local funcdebug ; funcdebug=0; summ=0;
 for HOST in $gw1 $gw2; do
    if [ "$silence" = "1" ]; then
      if [ "$HOST" = "$gw2" ]; then 
	$ping -i $pingtimeout -c 3 -I 212.38.105.2 $HOST 1>$null 2>$null 3>$null;
	else
	$ping -i $pingtimeout -c 3 -I 195.209.37.26 $HOST 1>$null 2>$null 3>$null;
      fi # [  "$HOST" = "$gw2" ]
     else
      if [ "$HOST" = "$gw2" ]; then 
       $ping -i $pingtimeout -c 3  -I 212.38.105.2 $HOST;
       else $ping -i $pingtimeout -c 3 -I 195.209.37.26 $HOST;
      fi # [ "$HOST" = "$gw2" ]
    fi # [ "$silence" = "1" ]
    result=$?; summ=`echo "$summ + $result" | $bc -l`;
    if [ "$result" = "1" ]; then echo \
     "the gateway $HOST is either unreachable either blocking our pings.";
     if [ "$HOST" = "$gw1" ]; then down=1;
      else if [ "$HOST" = "$gw2" ]; then down=2; fi
     fi
     
     else
      [ "$verbose" = "1" ] && echo -e "\t\tGateway HOST $HOST seem to be OK.\n"
    fi
 done
 [ "$funcdebug" = "1" ] && echo "\$summ=$summ";
 return $summ;
}

# should be silent if param is 0(all OK), should warn if param is 2(both down),
# should warn if param is 1(1 of 2 down)
function send_alert()
{
 #2do: email & syslogd notifications.
    if [ "$1" = "0" ]; then return 0; fi
    
    if [ "$1" = "2" ]; then
     echo -e "\n(!)\tAlert: Both your gateways seem to be down!\n";
    fi
    
    if [ "$1" = "1" ]; then 
     echo -e "\n(!)\tAlert: One of your gateways seem to be down:\n";
     if [ "$down" = "1" ]; then
      echo -e "\n(!)\tThe gateway $gw1 doesn't answer for our ping probes!\n";
     fi
     if [ "$down" = "2" ]; then
      echo -e "\n(!)\tThe gateway $gw2 doesn't answer for our ping probes!\n";
     fi
    fi

    if [ "$1" = "3" ]; then
    echo -e "\nNamed is NOT running (or pid wrong). Trying to restart.\n";
    echo -e \
    "\nPlease check logs & $0 for possible reasons that this has happend.\n";
    fi

    if [ "$1" = "4" ]; then
	echo -e \
  "\nEven when DNS server is seem to be running there problems w/ \
 host-reachability for some hosts:\n";
	echo -e \
  "\n$h4s & $h4n defined as the same host & ping returns diffrent return codes \
 for them.\n";
  echo -e "\nPlease do somthing by hands - this script is just a checker.\n";
  echo -e "\nThis may happen either on your local DNS errors, either";
  echo -e "if host list used for check for now contains the only hosts blocking ICMP\n";
  echo -ne "\n\tCurrent time is: "; date +%T; echo "," ; date +%d.%m.%Y;
  echo -e "\nThanks for attantion, your check script $0 .\n";
  
    fi
    
    if [ "$1" = "5" ]; then
      echo -e \
      "\nThe foreign segment of the internet seam to be UNREACHABLE.\n";
      echo -e "\nPlease do somthing by hands - this script is just a checker.\n";
      echo -e "\nThis may happen either on your UPstream provider errors, \
either if host list used for check for now contains the only hosts blocking \
ICMP\n";
      echo -ne "\n\tCurrent time is: "; date +%T; echo "," ; date +%d.%m.%Y;
      echo -e "\nThanks for attantion, your check script $0 .\n";
    fi

    if [ "$1" = "6" ]; then
	echo -e \
  "\nThe russian segment of the internet seam to be UNREACHABLE.\n";
	echo -e "\nPlease do somthing by hands - this script is just a \
checker.\n";
	echo -e "\nThis may happen either on your UPstream provider errors, \
either if host list used for check for now contains the only hosts blocking \
ICMP\n";
	echo -ne "\n\tCurrent time is: "; date +%T; echo "," ; date +%d.%m.%Y;
	echo -e "\nThanks for attantion, your check script $0 .\n";
    fi

    if [ "$1" = "6" ]; then
	echo -e "\nWarning! Remote DNS does not reachable.";
	echo -e "Please do somthing by hands - this script is just a checker.\n";
    fi

}

# Just changes routing. NAT has to be already configured to accept
# connections on both external interface for this to work transparently.
# Elsewhere scripts shell change.
function change_default_link()
{
 # 2do: add some intellect to detect what line is in use currently & if its
 # state didn't change - do nothing.
 if [ "$down" = "1" ]; then
  cp	/etc/sysconfig/network.def_gw=212.38.105.1		\
	/etc/sysconfig/network
  cp	/etc/sysconfig/static-routes.primary=212.38.105.1	\
	/etc/sysconfig/static-routes
  /etc/rc.d/init.d/network restart
  route add default gw 195.209.37.25 metric 1
  /etc/rc.d/init.d/firewall+nat:only_eth2.pl start
 fi

 if [ "$down" = "2" ]; then
  cp	/etc/sysconfig/network.def_gw=195.209.37.25		\
	/etc/sysconfig/network
  cp	/etc/sysconfig/static-routes.primary=195.209.37.25	\
	/etc/sysconfig/static-routes
  /etc/rc.d/init.d/network restart
  route add default gw 212.38.105.1 metric 1
  /etc/rc.d/init.d/firewall+nat:only_eth1.pl start
 fi
}

############ programm work start.
[ "$verbose" = "1" ] && echo
check_gateways; 
retcode=$?; 
send_alert $retcode;
if [ "$retcode" = "1" ]; then change_default_link; fi
check_does_dns_runs;
check_hosts_reachability;
check_remote_dns;
