#!/bin/sh

# Petit script custom pour vérifier le nombre de connexions sur netstat
# GPL v3+ (copyright chl-dev@bugness.org)

# Default values
RANGE_WARNING="1:50"
RANGE_CRITICAL="1:100"

# Output
OUTPUT_EXIT_STATUS=0
OUTPUT_DETAIL_WARNING=""
OUTPUT_DETAIL_CRITICAL=""
OUTPUT_PERFDATA=""

PROGPATH=$( echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,' )
REVISION="0.1"

# Stop at the first non-catched error
set -e

# Include check_range()
. $PROGPATH/utils.sh

#
# Fonction d'aide
#
usage() {
	cat <<EOF
Usage :
  $0 [-w warning_range] [-c critical_range] -p port [[-w...] -p port] ...

Example :
  ./check_netstat_connectioncount.sh -w 50 -c 100 -p 80

Note: Since the port is checked against the lastest ranges given, order
      of the arguments is important. Ex:
      ./check_netstat_connectioncount.sh -w 1:5 -c 1:10 -p 22 -p listen-unix:X11 -w 1:50 -c 1:100 -p 80 -p 443

Special values for 'port' :
	all
	all-ipv4
	all-ipv6
	listen
	listen-ipv4
	listen-ipv6
	listen-unix
	listen-unix:PATTERN

Default values:
	warning_range:	$RANGE_WARNING
	critical_range:	$RANGE_CRITICAL
EOF
}

check_range_syntax() {
	check_range 0 "$1" >/dev/null 2>&1
	if [ "$?" -eq "2" ]; then
		return 1
	fi
	return 0
}

# Some early checks
for i in netstat ss; do
	if which "$i" >/dev/null 2>&1 ; then
		COMMAND_SYS="$i"
		break
	fi
done
if [ -z "$COMMAND_SYS" ]; then
	echo "UNKNOWN 'netstat' and 'ss' not found."
	exit 1
fi

#
# Gestion des paramètres
#
while getopts hw:c:p: f; do
	case "$f" in
		'h')
			usage
			exit
			;;

		'w')
			if check_range_syntax "$OPTARG" >/dev/null; then
				RANGE_WARNING="$OPTARG"
			else
				echo "UNKNOWN: invalid range."
				exit 3
			fi
			;;

		'c')
			if check_range_syntax "$OPTARG" >/dev/null; then
				RANGE_CRITICAL="$OPTARG"
			else
				echo "UNKNOWN: invalid range."
				exit 3
			fi
			;;

		'p')
			# Ce n'est pas très propre, mais on gère tout ici plutôt que de remplir
			# un buffer et de le traiter ensuite
			# Note : grep renvoie un code d'erreur 1 s'il n'y a pas de résultat,
			#        d'où l'ajout d'un || true sur lui uniquement.
			LABEL="$OPTARG"
			case "$OPTARG" in
				'all')
					CPT="$( $COMMAND_SYS -taun  | tail -n +2 | wc -l )"
					PORT_NUMBER='all'
					;;
				'all-ipv4')
					CPT="$( $COMMAND_SYS -taun4 | tail -n +2 | wc -l )"
					PORT_NUMBER='all-ipv4'
					;;
				'all-ipv6')
					CPT="$( $COMMAND_SYS -taun6 | tail -n +2 | wc -l )"
					PORT_NUMBER='all-ipv6'
					;;
				'listen')
					CPT="$( $COMMAND_SYS -tlun  | tail -n +2 | wc -l )"
					PORT_NUMBER='listen'
					;;
				'listen-ipv4')
					CPT="$( $COMMAND_SYS -tlun4 | tail -n +2 | wc -l )"
					PORT_NUMBER='listen-ipv4'
					;;
				'listen-ipv6')
					CPT="$( $COMMAND_SYS -tlun6 | tail -n +2 | wc -l )"
					PORT_NUMBER='listen-ipv6'
					;;
				'listen-unix')
					CPT="$( $COMMAND_SYS -xl | tail -n +2 | wc -l )"
					PORT_NUMBER='listen-unix'
					;;
				'listen-unix:'*)
					CPT="$( $COMMAND_SYS -xl | tail -n +2 | grep "$( echo "$OPTARG" | sed 's/^listen-unix://' )" | wc -l )"
					PORT_NUMBER=$OPTARG  # risque de bug côté superviseur ?
					;;
				*)
					PORT_NUMBER=$( printf "%d" "$OPTARG" )
					LABEL="port$PORT_NUMBER"
					CPT="$( $COMMAND_SYS -tauen | sed 's/[[:space:]]\+/\t/g' | cut -f 4 | ( grep -c ":$PORT_NUMBER$" || true ) )"
					;;
			esac

			# mémo : 'label'=value[UOM];[warn];[crit];[min];[max]
			OUTPUT_PERFDATA=$( printf "%s'%s'=%d;%s;%s;0;" \
					"$( test -n "$OUTPUT_PERFDATA" && echo "$OUTPUT_PERFDATA " )" \
					"$LABEL" \
					"$CPT" \
					"$RANGE_WARNING" \
					"$RANGE_CRITICAL" )

			if check_range "$CPT" "$RANGE_CRITICAL"; then
				OUTPUT_EXIT_STATUS=2
				OUTPUT_DETAIL_CRITICAL="$OUTPUT_DETAIL_CRITICAL Port:$PORT_NUMBER($CPT conn.)"
			elif check_range "$CPT" "$RANGE_WARNING"; then
				if [ "$OUTPUT_EXIT_STATUS" -eq 0 ]; then
					OUTPUT_EXIT_STATUS=1
				fi
				OUTPUT_DETAIL_WARNING="$OUTPUT_DETAIL_WARNING Port:$PORT_NUMBER($CPT conn.)"
			fi
			;;

		\?)
			usage
			exit 1
			;;
	esac
done

case "$OUTPUT_EXIT_STATUS" in
	'0')
		printf "OK ($COMMAND_SYS)"
		;;
	'1')
		printf "WARNING ($COMMAND_SYS) %s" "$OUTPUT_DETAIL_WARNING"
		;;
	'2')
		printf "CRITICAL ($COMMAND_SYS) %s" "$OUTPUT_DETAIL_CRITICAL"
		;;
	*)
		printf "UNKNOWN"
		;;
esac

printf "|%s\n" "$OUTPUT_PERFDATA"
# on supprime les retours à la ligne
exit $OUTPUT_EXIT_STATUS