#!/bin/bash
#< Script to pingscan a subnet and report on host status

AWK="/usr/bin/awk"
BASENAME="/usr/bin/basename"
ECHO="/usr/bin/echo"
EGREP="/bin/egrep"
HOST="/usr/bin/host"
PING="/bin/ping"
SEQ="/usr/bin/seq"
TR="/usr/bin/tr"

THISPROG=$( ${BASENAME} $0 )

function print_error {
   ${ECHO} "Error: $@" >&2
}

function print_usage {
   {
      ${ECHO} "Usage: ${THISPROG} [-r] <network_address>"
      ${ECHO} "          -r   Attempt to resolve addresses"
   } >&2
}

function check_network_address {
   # We only scan /24's at the moment
   NUM_OCTETS=$( ${ECHO} "${NETWORK_ADDRESS}" | ${AWK} -vFS='.' '{print NF}' )
   if [ "${NUM_OCTETS}" -ne "4" ]; then
      print_error "Malformed network address" && exit 1
   fi
   ${ECHO} "${NETWORK_ADDRESS}" | ${TR} '.' '\n' | while read OCTET; do
      ${ECHO} "${OCTET}" | ${EGREP} '^[0-9]+$' >/dev/null 2>&1
      if [ "$?" -ne "0" ]; then
         print_error "All octets must be integer values" && exit 1
      fi
      if [ "${OCTET}" -lt "0" -o "${OCTET}" -gt "255" ]; then
         print_error "Octet out of range" && exit 1
      fi
   done
}

function perform_ping {
   for ADDR in $( ${SEQ} 1 255 ); do
      PING_THIS=${NETWORK_ADDRESS%.*}.${ADDR}
      if [ "${RESOLVE}" -eq "1" ]; then
         RESOLVED_HOST=$( ${HOST} -W 1 ${PING_THIS} | ${AWK} 'NR==1{print $NF}' )
         RESOLVED_HOST="[${RESOLVED_HOST}]"
         case ${RESOLVED_HOST} in
            *NXDOMAIN*) RESOLVED_HOST="[Unable to resolve host]" ;;
            *         ) ;;
         esac
      fi
      ${PING} -c 1 -w 1 ${PING_THIS} >/dev/null 2>&1 
      if [ "$?" -eq "0" ]; then
         ${ECHO} "${PING_THIS} appears to be UP ${RESOLVED_HOST}"
      else
         ${ECHO} "${PING_THIS} appears to be DOWN ${RESOLVED_HOST}"
      fi
   done
}

if [ "$#" -lt "1" -o "$#" -gt "2" ]; then
   print_usage && exit 1
fi

if [ "$1" = "-r" ]; then
   RESOLVE=1
   NETWORK_ADDRESS="$2"
else
   if [ "$#" -ne "1" ]; then
      print_usage && exit 1
   fi
   RESOLVE=0
   NETWORK_ADDRESS="$1"
fi

check_network_address
perform_ping

exit 0