#!/bin/bash

hostname=""
community=""
counter=""
perfName=""
iname=""
inum=""
debug=""
min=""
max=""
warn=""
crit=""
exitCode="0"
statusText="OK"

# snmpwalk -v 2c -c public 192.168.0.1 1.3.6.1.2.1.2.2.1.2 | sed -e "s/^IF-MIB::ifDescr.//" | awk '{print $NF, $1}' | while read iname inum; do echo "$iname"; for oid in 1.3.6.1.2.1.2.2.1.5 1.3.6.1.2.1.2.2.1.10 1.3.6.1.2.1.2.2.1.16 1.3.6.1.2.1.2.2.1.20; do snmpget -v 2c -c public 192.168.0.1 ${oid}.${inum}; done; done
# current bandwidth snmpwalk -v 2c -c public 192.168.1.1 1.3.6.1.2.1.2.2.1.5
# octets received snmpwalk -v 2c -c public 192.168.1.1 1.3.6.1.2.1.2.2.1.10
# octets sent snmpwalk -v 2c -c public 192.168.1.1 1.3.6.1.2.1.2.2.1.16
# error octets 1.3.6.1.2.1.2.2.1.20

do_debug() {
  [ -z "$debug" ] && return
  echo "DEBUG: $*" >&2
}

do_help() {
  echo "Usage: $0 -H <hostname> -C <community> [-I <interface name> | -i <inum>) -t (b|r|s|e) [-w <warn>] [-c <crit>]"
# -w <warn> -c <crit> -m <min> -M <max> [-d] (kp | flux)"
  exit
}

while getopts "dhC:H:I:i:t:w:c:" opt; do
  case "$opt" in
    H) hostname="$OPTARG";;
    I) iname="$OPTARG";;
    i) inum="$OPTARG";;
    t) counter="$OPTARG";;
    C) community="$OPTARG";;
    w) warn="$OPTARG";;
    c) crit="$OPTARG";;
    h) do_help;;
    d) debug="true";;
  esac
done
shift $((OPTIND - 1))
command="$@"
do_debug "host=$hostname iname=$iname inum=$inum counter=$counter warn=$warn crit=$crit"
[ -z "$hostname" ] && echo "No hostname specified." && exit 0
[ -z "$community" ] && echo "No community specified." && exit 0

check_threshold() {
  local val=$1
  local range=$2
  local alert_inside=0
  local start=0
  local end="inf"
  # Handle empty thresholds safely
  if [[ -z "$range" ]]; then return 0; fi
  # Check for the inside-range prefix '@'
  if [[ "$range" == @* ]]; then
    alert_inside=1
    range="${range#@}" # Strip the '@'
  fi
  # Parse start and end values out of the range colon (:) syntax
  if [[ "$range" == *:* ]]; then
    start="${range%%:*}"
    end="${range#*:}"
    # Handle implicit defaults
    [[ -z "$start" ]] && start=0
    [[ "$start" == "~" ]] && start="-inf"
    [[ -z "$end" ]] && end="inf"
  else
    # No colon: Shorthand for 0:X
    start=0
    end="$range"
  fi
  # Evaluate logic using bc (handles floats and floating point math)
  local outside=0
  # Check lower boundary; inclusive of endpoints
  if [[ "$start" != "-inf" ]]; then
    if (( $(echo "$val < $start" | bc -l) )); then outside=1; fi
  fi
  # Check upper boundary; inclusive of endpoints
  if [[ "$end" != "inf" ]]; then
    if (( $(echo "$val > $end" | bc -l) )); then outside=1; fi
  fi
  # Return true/false based on whether the @ symbol inverted the logic
  if [[ $alert_inside -eq 1 ]]; then
    # Alert if INSIDE the range
    if [[ $outside -eq 0 ]]; then return 1; else return 0; fi
  else
    # Alert if OUTSIDE the range (Standard Nagios Behavior)
      if [[ $outside -eq 1 ]]; then return 1; else return 0; fi
  fi
}

do_snmp() {
  myNum="$1"
  myOid="$2"
  myName="$3"
  do_debug "checking $hostname for $myName (inum: $myNum) on $myOid:"
  output=$(snmpget -v 2c -c $community $hostname ${myOid}.${myNum} | awk '{print $NF}')
  if [ -z "$output" ]; then
    echo "UNKNOWN: snmpget error"
    exit 3
  else
    echo "$output"
  fi
}

do_stats() {
  myNum="$1"
  myName="$2"
  myOid=""
  do_debug "do_stats: myNum=$myNum myName=$myName myOid=$myOid"
  case "$counter" in
    b) counter="Bandwidth"; perfName="'bw_bytes'"; myOid="1.3.6.1.2.1.2.2.1.5";;
    r) counter="Received"; perfName="'bytes_recv'"; myOid="1.3.6.1.2.1.2.2.1.10";;
    s) counter="Sent"; perfName="'bytes_sent'"; myOid="1.3.6.1.2.1.2.2.1.16";;
    e) counter="Errors"; perfName="'bytes_errors'"; myOid="1.3.6.1.2.1.2.2.1.20";;
    *) echo "Invalid counter type specified."; exit 0;;
  esac
  do_debug "do_stats: do_snmp $myNum $myOid $myName"
  value=$(do_snmp $myNum $myOid $myName)
  # CRITICAL check must always run first to ensure it takes precedence
  if ! check_threshold "$value" "$crit"; then
    exitCode=2
    statusText="CRITICAL"
  elif ! check_threshold "$value" "$warn"; then
    exitCode=1
    statusText="WARNING"
  fi
#  [ "$value" != "?" ] && value=$(printf "%.4f" "$value")
  echo "$myName $counter $statusText: $value|$perfName=${value}B;$warn;$crit;$min;$max"
  exit $exitCode
}

if [ -n "$inum" ]; then
  do_debug "Specified inum=$inum"
  do_stats $inum
else
  do_debug "Did not specify an inum"
  do_debug "snmpwalk -v 2c -c $community $hostname 1.3.6.1.2.1.2.2.1.2"
  snmpwalk -v 2c -c $community $hostname 1.3.6.1.2.1.2.2.1.2 | sed -e "s/^IF-MIB::ifDescr.//" | awk '{print $1, $NF}' | while read myNum myName; do
    [ -z "$iname" -a -z "$inum" ] && echo "iname: $myName (inum: $myNum)" && continue  # Show interfaces if we didn't specify one
    [ "$iname" != "$myName" ] && continue
    do_debug "Found $iname (ifnum: $myNum)"
    do_stats $myNum
  done
fi
