#!/bin/bash

# check_haproxy_stunnel.sh - check stunnels configs in /etc/haproxy/conf.d                          

# This script will check if stunnels brought up by haproxy extra-configs (in
# conf.d directory) are up and OK.
#
# stunnel-193.200.227.65-cert-name (something dash IP dash cert-name, which can contain further dashes)
#
# Additionally, the script assumes and checks:
#   a) IP 193.200.227.65 is an alias "of" lo interface (the interface can be changed with -i switch)
#   b) a PEM file /etc/pki/cert-name.pem exits
#
# Additionally, this script assumes:
#   a) stunnels bind to port 443
#   b) stunnels wraps traffic from port 80 on the same IP
#
# This script does monitoring for stunnels set up by script at http://orfika.net/src/stunnel-script.sh

# Copyright 2012 Rafał Frühling <rafamiga@gmail.com>

# last revision: $Date: 2012-01-26 14:24:17 +0100 (czw) $

# LICENCE: GPL
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# you should have received a copy of the GNU General Public License
# along with this program (or with Nagios); if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA

PROGNAME=`basename $0`
PROGPATH=`echo $0 | /bin/sed -e 's,[\\/][^\\/][^\\/]*$,,'`
REVISION=`echo '$Revision: 17714 $' | sed -e 's/[^0-9.]//g'`

ip_exe=/sbin/ip
netstat_exe=/bin/netstat

STATE_UNKNOWN=3
STATE_CRITICAL=2
STATE_WARNING=1
STATE_OK=0

print_usage() {
    echo "Usage: ${PROGNAME} -h"
    echo "Usage: ${PROGNAME} -v"
    echo "Usage: ${PROGNAME} [-d DIRECTORY] [-i INTERFACE] [-n] [-x] [-e IP[,IP[,IP...]]]"
    echo ""
    echo "    -d <directory>: the directory in which to look for stunnel definitions (default: /etc/haproxy/conf.d)"
    echo "    -i <interface}: look for aliases of this interface (default: lo);"
    echo "                    use 'any' to search in all interfaces"
    echo "    -e <excluded IPs>: do not report IP(s) missing; use commas to separate, for ex. -e 1.2.3.4,2.3.4.5"
#    echo "    -a <ip>: main IP address of the interface (with netmask; default: 127.0.0.1/8)"
    echo "    -n: do not fail if stunnels are not up (warn only)"
#    echo "    -6: check IPv6 addresses as well as IPv4"
    echo "    -x: do not report any extra config(s) found"
    }
 
print_help() {
    print_revision "$PROGNAME" $REVISION
    echo ""
    print_usage
    echo ""
    echo "Plugin to check if stunnels defined in /etc/haproxy/conf.d directory are up."
    echo ""
    }

## No command line arguments are supplied for this script. Print help.
#
#if [ "$#" -eq "0" ]; then
#    print_usage
#    exit ${STATE_UNKNOWN}
#fi

# Print help with --help

if [[ ("$#" -eq "1") && ("$1" = "--help") ]]; then
    print_help
    exit ${STATE_UNKNOWN}
fi

HAPROXY_EXTRACONF_DIR=/etc/haproxy/conf.d
FAIL_MISSING_STU=1 # stunnel not up
FAIL_MISSING_IPS=1 # no IP for stunnel
IGNORE_EXTRA_STU=0 # check for extra configs

USE_IPV6=0
INT_SRC=lo
#INT_ADDR="127.0.0.1/8"
EXCLUDE_IPS=""

https_port=443
http_port=80
script_glob=stunnel

while getopts "vhne:d:i:x" option
do
    case ${option} in
        h     ) print_help
            exit ${STATE_UNKNOWN};;
        v     ) print_revision "${PROGNAME}" ${REVISION}
            exit ${STATE_UNKNOWN};;
        n     ) FAIL_MISSING_IPS=0;;
        d     ) HAPROXY_EXTRACONF_DIR=${OPTARG};;
        i     ) INT_SRC=${OPTARG};;
        e     ) EXCLUDE_IPS=`echo "${OPTARG}" | /bin/sed -e 's!,! !g'`;;
#        a     ) INT_ADDR=${OPTARG};;
#        6     ) USE_IPV6=1;;
        x     ) IGNORE_EXTRA_STU=1;;
        *     ) print_usage
            exit ${STATE_UNKNOWN};;   # DEFAULT
    esac
done

if [ ! -d "${HAPROXY_EXTRACONF_DIR}" ] || [ ! -r "${HAPROXY_EXTRACONF_DIR}" ]; then
    echo "UNKNOWN - HAPROXY extra config directory '${HAPROXY_EXTRACONF_DIR}' is missing or unreadable by '${USER}' user."
    exit ${STATE_UNKNOWN}
fi

if [ ! -x ${ip_exe} ]; then
    echo "UNKNOWN - can't run plugin, '${ip_exe}' binary not found or unreadable by '${USER}' user."
    exit ${STATE_UNKNOWN}
fi

if [ ! -x ${netstat_exe} ]; then
    echo "UNKNOWN - can't run plugin, '${netstat_exe}' binary not found or unreadable by '${USER}' user."
    exit ${STATE_UNKNOWN}
fi

if [ "${INT_SRC}" == "any" ] ; then
    TRACE=`${ip_exe} addr list 2>&1`
else
    TRACE=`${ip_exe} addr list dev ${INT_SRC} 2>&1`
fi

if [ -z "${TRACE}" ]; then
    echo "UNKNOWN - can't run plugin, either interface '${INT_SRC}' does not exist or '${ip_exe}' binary failed to gather information about it."
    exit ${STATE_UNKNOWN} 
fi

NETSTAT_OUT=`${netstat_exe} -tpnl 2>&1`

if [ -z "${NETSTAT_OUT}" ]; then
    echo "UNKNOWN - can't run plugin, either interface '${INT_SRC}' does not exist or '${ip_exe}' binary failed to gather information about it."
    exit ${STATE_UNKNOWN} 
fi

haproxy_conf_d_files=`dir -BU "${HAPROXY_EXTRACONF_DIR}"`

if [ -z "${haproxy_conf_d_files}" ]; then
    echo "WARNING - no files found in '${HAPROXY_EXTRACONF_DIR}'"
    exit ${STATE_WARNING}
fi

# checks

MISSING_IPS=""
MISSING_STU=""
EXTRA_STU=""

for intf in ${haproxy_conf_d_files}; do
    scriptname=${intf%%-*}

    # not a "stunnel" file
    if [ "${scriptname}" != "${script_glob}" ]; then
    	continue
    fi

    moremore="${intf#*-}"
    ipalias=${moremore%%-*}
    certname=${moremore#*-}

    ipalias_nonetmask=${ipalias}

    if [ "${ipalias}" != "${ipalias#*/}" ]; then
        ipalias_nonetmask="${ipalias#*/}"
    fi

# check if a tunnel is defined but not up

    IS_BOUND=`echo "${NETSTAT_OUT}" | grep -q -F "${ipalias_nonetmask}:${https_port}"`

    if [ $? -ne 0 ]; then
        MISSING_STU="${moremore} ${MISSING_STU}"
    fi

# check if stunnel file is present for non-existent IP; ignore exluded IP ["-e" option]

    if [ "${ipalias}" == "${ipalias#*/}" ]; then
        ipalias="${ipalias}/"
    fi

    CHECKED_OK=`echo "${TRACE}" | grep -q -F ${ipalias}`

    while [ $? -ne 0 ]; do
        if [ -n "${EXCLUDE_IPS}" ]; then
            for excl in "${EXCLUDE_IPS}"; do
                if [ "${ipalias_nonetmask}" == "${excl}" ]; then
                    break 2 # out of while loop
                fi
            done
        fi

        MISSING_IPS="${ipalias_nonetmask} ${MISSING_IPS}"
	break
    done

# check if stunnel file is defined but loalias script is missing

    if [ ! -e "${HAPROXY_EXTRACONF_DIR}/${INT_SRC}alias-${ipalias}" ]; then
        EXTRA_STU="${moremore} ${MISSING_STU}"
    fi

done

# very important, report it first

if [ -n "${MISSING_STU}" ]; then
    if [ ${FAIL_MISSING_STU} -eq 0 ]; then
        echo "WARNING - stunnel definition found but process not running/bound: ${MISSING_STU}"
        exit ${STATE_WARNING}
    else
        echo "CRITICAL - stunnel definition found but process not running/bound: ${MISSING_STU}"
        exit ${STATE_CRITICAL}
    fi
fi

# less important, report it later

if [ -n "${MISSING_IPS}" ]; then
    if [ "${INT_SRC}" != "any" ]; then
        MSG="stunnel definition IP(s) missing on interface '${INT_SRC}': ${MISSING_IPS}"
    else
        MSG="stunnel definition IP(s) missing (any interface): ${MISSING_IPS}"
    fi

    if [ ${FAIL_MISSING_IPS} -eq 0 ]; then
        echo "WARNING - ${MSG}"
        exit ${STATE_WARNING}
    else
        echo "CRITICAL - ${MSG}"
        exit ${STATE_CRITICAL}
    fi
fi

# leftovers, report it last

if [ ${IGNORE_EXTRA_STU} -ne 0 ] && [ -n "${EXTRA_STU}" ]; then
    echo "WARNING - leftover stunnel definition found: ${EXTRA_STU}"
    exit ${STATE_WARNING}
fi

# I'm fine, thank you

echo "OK - haproxy stunnel(s) on '${INT_SRC}' OK."
exit ${STATE_OK}
