#!/bin/sh
#!/bin/sh
# Description: Basic network check
# Author: Swift Griggs <sgriggs@parsec.com>
# 
# [Log]
#   Apr-2021: Initial version written for demonstration during MEP webinar at PARSEC
#

# Do not depend on an upstream alerter.  Send directly from this script. 
# Set to "NO" for disable or enter your preferred email or whitespace
# delimited list to enable.
EMAIL_ALERTS=NO

# Without this on, the script likely will only output "OK"
VERBOSE=YES

# Cache files
NETSTAT_CHECKSUM_CACHE=/var/tmp/netstat_checksum.cache

# Globals in use
RETURN_VALUE=0
FIRST_RUN=0

# Send log messages and debug chatter where it's wanted
geko(){

  # We'll use 'logger' if it's found	  
  which logger >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    # use the logger program for writing to syslog
    Log=logger
  else
    # essentially disable logging 
    Log="echo >/dev/null # "
  fi 
  

  if [ $VERBOSE = "YES" ]; then
    echo "$1"
    $Log $1
  else
    # Do not echo to the screen but log to syslog
    $Log $1
  fi 
}

# Make sure we have what we need to run the script
sanity_check(){

  # make sure we can create files in /tmp
  echo testing > /tmp/test.$$
  if [ $? -ne 0 ]; then
    # Something is wrong with /tmp
    geko "ERROR: Cannot create a test file in /tmp!"
    exit 2
  else
    rm /tmp/test.$$
  fi 

  # Mailx is needed for the email sending.  However, it's not fatal if we
  # don't have it.
  which mailx >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    geko "WARNING: The 'mailx' program is not in your path. This script won't be able to send email alerts!"
  fi 

  # Needed to create a checksum from the netstat output. 
  which cksum >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    geko "ERROR: The 'cksum' program is not in your path. It's required. Fatal."
    exit 10
  fi 

  # without netstat we cannot check the network!
  which netstat >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    geko "ERROR: The 'netstat' program is not in your path. It's required. Fatal."
    exit 11
  fi 

  which awk >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    # cut won't work on Solaris properly (cksum uses tabs on Solaris). We need awk. 
    geko "ERROR: The 'awk' program is not in your path. It's required. Fatal."
    exit 11
  fi 

  # Be nice to have logger for syslog entries.
  which logger >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    geko "WARNING: The 'logger' program is not in your path. It's used for syslog entries. Continuing."
  fi   
}


send_email_alert(){
  IS_EMAIL_ENABLED=`echo $EMAIL_ALERTS | grep '@' | wc -l`
  if [ $IS_EMAIL_ENABLED -ne 1 ]; then
    # Email feature is disabled. Do nothing.
    return 0
  fi 

  # Send the alert 
  which mailx >/dev/null 2>&1 
  if [ $? -eq 0 ]; then
    # we have mailx to send a message. Use it. 
    MYNAME=`uname -n`
    NOW=`date`
    echo $1 | mailx -s "Network Alert from $MYNAME detected at $NOW" $EMAIL_ALERTS
  fi 
}

parse_netstat(){
  # init the old value
  OLD_CACHE_VALUE='00000'
  
  # Build the cache if we don't have it.
  if ! [ -r "$NETSTAT_CHECKSUM_CACHE" ]; then
    netstat -s | egrep -i 'fail|err|warn|bad|over' | cksum | awk '{print $1}' > "$NETSTAT_CHECKSUM_CACHE"
    OLD_CACHE_VALUE=`cat "$NETSTAT_CHECKSUM_CACHE"`
  fi
  
  NEW_CACHE_VALUE=`netstat -s | egrep -i 'fail|err|warn|bad|over' | cksum | awk '{print $1}'`

  if [ $OLD_CACHE_VALUE -ne $NEW_CACHE_VALUE ]; then
    geko "No new network errors or warnings."
    return 0
  else
    geko "There are new network errors or warnings"
    MYNAME=`uname -n`
    NOW=`date`
    send_email_alert "There are new network errors or warnings on $MYNAME detected at $NOW"
    return 1 
  fi   
}

# main()

# Add a user-friendly console output one-liner.  No 'geko' here.  Some
# monitoring software likes *some* response to act as a sort of keepalive
# string or sanity check beyond the return value / exit code.
if [ $RETURN_VALUE -eq 0 ]; then
  echo "OK"
else
  if [ $FIRST_RUN -eq 1 ]; then
    # There read failures on bogus disk entries.
    # Do not squawk about that on a first-run.
    echo "OK"
  else
    echo "ERROR: One or more failures or runtime errors was detected."
  fi
fi

# Leave the caller with a numeric value. Plays nice with 
# monitoring software expecting a non-zero exit being in error
exit $RETURN_VALUE
