446 lines
9.8 KiB
Bash
Executable File
446 lines
9.8 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
usage() {
|
|
echo "Usage: $0 -u <url> [-w <warning>] [-c <critical>] [-C <contains>] [-L] [-I] [-H <headers>] [-p] [-R] [-s]"
|
|
echo "[Arguments]:
|
|
-u Specify the URL to check (required).
|
|
-w Set the warn level for response time (default: 1 second).
|
|
-c Set the critical level for response time (default: 2 seconds).
|
|
-C If the body does not contain this string, return CRITICAL.
|
|
-L Follow redirects.
|
|
-I Insecure mode (--insecure).
|
|
-H Specify headers. Formatted like \"Header1: value,Header2: value\"
|
|
-p Print the curl command and exit
|
|
-R Set curl --resolve option.
|
|
-M Set the HTTP mode (default: GET)
|
|
-t Timeout in seconds
|
|
-s Ignore the response status code.
|
|
-e Expected status code.
|
|
-S Sanitize HTML when printing to console. Good for Icinga2 Web.
|
|
-n Don't return any perfdata if the status code was not 200."
|
|
exit 3
|
|
}
|
|
|
|
# Default values
|
|
WARN_TIME=700
|
|
CRIT_TIME=1000
|
|
FOLLOW_REDIRECTS=""
|
|
INSECURE=""
|
|
HEADERS=""
|
|
PRINT_CURL=""
|
|
RESOLVE=""
|
|
IGNORE_STATUS=""
|
|
TIMEOUT="30"
|
|
HTTP_METHOD="-X GET"
|
|
EXPECTED_STATUS_CODE=""
|
|
SANITIZE_HTML=false
|
|
DISABLE_PERFDATA=false
|
|
|
|
# Parse arguments
|
|
while getopts "u:w:c:C:LH:M:IpR:st:e:hSn" opt; do
|
|
case $opt in
|
|
u)
|
|
URL="$OPTARG"
|
|
;;
|
|
w)
|
|
WARN_TIME="$OPTARG"
|
|
;;
|
|
c)
|
|
CRIT_TIME="$OPTARG"
|
|
;;
|
|
C)
|
|
CRIT_STRING="$OPTARG"
|
|
;;
|
|
L)
|
|
FOLLOW_REDIRECTS="-L"
|
|
;;
|
|
I)
|
|
INSECURE="--insecure"
|
|
;;
|
|
H)
|
|
HEADERS="--header $OPTARG"
|
|
;;
|
|
p)
|
|
PRINT_CURL="yes"
|
|
;;
|
|
R)
|
|
RESOLVE="--resolve $OPTARG"
|
|
;;
|
|
s)
|
|
IGNORE_STATUS="yes"
|
|
;;
|
|
t)
|
|
TIMEOUT="--max-time $OPTARG"
|
|
;;
|
|
M)
|
|
HTTP_METHOD="-X $OPTARG"
|
|
;;
|
|
e)
|
|
EXPECTED_STATUS_CODE="$OPTARG"
|
|
;;
|
|
h)
|
|
usage
|
|
;;
|
|
S)
|
|
SANITIZE_HTML=true
|
|
;;
|
|
n)
|
|
DISABLE_PERFDATA=true
|
|
;;
|
|
*)
|
|
echo "Invalid option: -$OPTARG" >&2
|
|
usage
|
|
exit 3
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Check if URL is provided
|
|
if [ -z "$URL" ]; then
|
|
echo "Usage: $0 -u URL [options]"
|
|
exit 3
|
|
fi
|
|
|
|
# Prepare curl command
|
|
CURL_CMD="curl -w %{http_code};%{time_total} -o /dev/null -s $HTTP_METHOD $FOLLOW_REDIRECTS $INSECURE $HEADERS $RESOLVE $TIMEOUT $URL"
|
|
|
|
# Print curl command if requested
|
|
if [ "$PRINT_CURL" = "yes" ]; then
|
|
echo "$CURL_CMD"
|
|
exit 0
|
|
fi
|
|
|
|
# Execute curl command
|
|
CURL_OUTPUT=$($CURL_CMD)
|
|
CURL_EXIT=$?
|
|
|
|
# Parse curl output
|
|
HTTP_CODE=$(echo "$CURL_OUTPUT" | cut -d ';' -f 1)
|
|
RESPONSE_TIME=$(echo "$CURL_OUTPUT" | cut -d ';' -f 2 | xargs printf "%0.2f\n")
|
|
|
|
# Check curl exit status
|
|
if [ $CURL_EXIT -ne 0 ]; then
|
|
case $CURL_EXIT in
|
|
1)
|
|
msg="CRITICAL - Unsupported protocol"
|
|
;;
|
|
2)
|
|
msg="CRITICAL - Failed to initialize"
|
|
;;
|
|
3)
|
|
msg="CRITICAL - Malformed URL"
|
|
;;
|
|
4)
|
|
msg="CRITICAL - Feature or option not enabled"
|
|
;;
|
|
5)
|
|
msg="CRITICAL - Couldn't resolve proxy"
|
|
;;
|
|
6)
|
|
msg="CRITICAL - Could not resolve host"
|
|
;;
|
|
7)
|
|
msg="CRITICAL - Could not connect to host"
|
|
;;
|
|
8)
|
|
msg="CRITICAL - Unknown FTP server response"
|
|
;;
|
|
9)
|
|
msg="CRITICAL - FTP access denied"
|
|
;;
|
|
10)
|
|
msg="CRITICAL - FTP accept failed"
|
|
;;
|
|
11)
|
|
msg="CRITICAL - FTP weird PASS reply"
|
|
;;
|
|
12)
|
|
msg="CRITICAL - FTP timeout during active session"
|
|
;;
|
|
13)
|
|
msg="CRITICAL - Unknown response to FTP PASV command"
|
|
;;
|
|
14)
|
|
msg="CRITICAL - Unknown FTP 227 format"
|
|
;;
|
|
15)
|
|
msg="CRITICAL - FTP cannot get host"
|
|
;;
|
|
16)
|
|
msg="CRITICAL - HTTP/2 error"
|
|
;;
|
|
17)
|
|
msg="CRITICAL - FTP could not set binary"
|
|
;;
|
|
18)
|
|
msg="CRITICAL - Partial file"
|
|
;;
|
|
19)
|
|
msg="CRITICAL - FTP could not download/access the given file"
|
|
;;
|
|
# Skipping 20 as it is not used
|
|
21)
|
|
msg="CRITICAL - Quote error"
|
|
;;
|
|
22)
|
|
msg="CRITICAL - Server returned http code >= 400"
|
|
;;
|
|
23)
|
|
msg="CRITICAL - Write error"
|
|
;;
|
|
# Skipping 24 as it is not used
|
|
25)
|
|
msg="CRITICAL - Upload failed"
|
|
;;
|
|
26)
|
|
msg="CRITICAL - Read error"
|
|
;;
|
|
27)
|
|
msg="CRITICAL - Out of memory"
|
|
;;
|
|
28)
|
|
msg="CRITICAL - Operation timeout"
|
|
;;
|
|
# Skipping 29 and 30 as they are not used
|
|
31)
|
|
msg="CRITICAL - FTP could not use REST"
|
|
;;
|
|
# Skipping 32 as it is not used
|
|
33)
|
|
msg="CRITICAL - HTTP range error"
|
|
;;
|
|
34)
|
|
msg="CRITICAL - HTTP post error"
|
|
;;
|
|
35)
|
|
msg="CRITICAL - A TLS/SSL connect error"
|
|
;;
|
|
36)
|
|
msg="CRITICAL - Bad download resume"
|
|
;;
|
|
37)
|
|
msg="CRITICAL - Couldn't read the given file when using the FILE:// scheme"
|
|
;;
|
|
38)
|
|
msg="CRITICAL - LDAP cannot bind"
|
|
;;
|
|
39)
|
|
msg="CRITICAL - LDAP search failed"
|
|
;;
|
|
# Skipping 40 and 41 as they are not used
|
|
42)
|
|
msg="CRITICAL - Aborted by callback"
|
|
;;
|
|
43)
|
|
msg="CRITICAL - Bad function argument"
|
|
;;
|
|
# Skipping 44 as it is not used
|
|
45)
|
|
msg="CRITICAL - Interface error"
|
|
;;
|
|
# Skipping 46 as it is not used
|
|
47)
|
|
msg="CRITICAL - Too many redirects"
|
|
;;
|
|
48)
|
|
msg="CRITICAL - Unknown option specified to libcurl"
|
|
;;
|
|
49)
|
|
msg="CRITICAL - Malformed telnet option"
|
|
;;
|
|
# Skipping 50 as it is not used
|
|
51)
|
|
msg="CRITICAL - The server's SSL/TLS certificate or SSH fingerprint failed verification"
|
|
;;
|
|
52)
|
|
msg="CRITICAL - Server returned empty response"
|
|
;;
|
|
53)
|
|
msg="CRITICAL - SSL crypto engine not found"
|
|
;;
|
|
54)
|
|
msg="CRITICAL - Cannot set SSL crypto engine as default"
|
|
;;
|
|
55)
|
|
msg="CRITICAL - Failed sending network data"
|
|
;;
|
|
56)
|
|
msg="CRITICAL - Failure receiving network data"
|
|
;;
|
|
# Skipping 57 as it is not used
|
|
58)
|
|
msg="CRITICAL - Problem with the local certificate"
|
|
;;
|
|
59)
|
|
msg="CRITICAL - Couldn't use the specified SSL cipher"
|
|
;;
|
|
60)
|
|
msg="CRITICAL - SSL/TLS connection problem"
|
|
;;
|
|
61)
|
|
msg="CRITICAL - Unrecognized transfer encoding"
|
|
;;
|
|
# Skipping 62 as it is not used
|
|
63)
|
|
msg="CRITICAL - Maximum file size exceeded"
|
|
;;
|
|
64)
|
|
msg="CRITICAL - Requested SSL (TLS) level failed"
|
|
;;
|
|
65)
|
|
msg="CRITICAL - Sending the data requires a rewind that failed"
|
|
;;
|
|
66)
|
|
msg="CRITICAL - Failed to initialize the OpenSSL SSL Engine"
|
|
;;
|
|
67)
|
|
msg="CRITICAL - The user name, password, or similar was not accepted and curl failed to log in"
|
|
;;
|
|
68)
|
|
msg="CRITICAL - File not found on TFTP server"
|
|
;;
|
|
69)
|
|
msg="CRITICAL - Permission problem on TFTP server"
|
|
;;
|
|
70)
|
|
msg="CRITICAL - Out of disk space on TFTP server"
|
|
;;
|
|
71)
|
|
msg="CRITICAL - Illegal TFTP operation"
|
|
;;
|
|
72)
|
|
msg="CRITICAL - Unknown TFTP transfer ID"
|
|
;;
|
|
73)
|
|
msg="CRITICAL - File already exists (TFTP)"
|
|
;;
|
|
74)
|
|
msg="CRITICAL - No such user (TFTP)"
|
|
;;
|
|
# Skipping 75 and 76 as they are not used
|
|
77)
|
|
msg="CRITICAL - Problem with reading the SSL CA cert"
|
|
;;
|
|
78)
|
|
msg="CRITICAL - The resource (file) referenced in the URL does not exist"
|
|
;;
|
|
79)
|
|
msg="CRITICAL - An unspecified error occurred during the SSH session"
|
|
;;
|
|
80)
|
|
msg="CRITICAL - Failed to shut down the SSL connection"
|
|
;;
|
|
# Skipping 81 as it is not used
|
|
82)
|
|
msg="CRITICAL - Could not load CRL file, missing or wrong format"
|
|
;;
|
|
83)
|
|
msg="CRITICAL - TLS certificate issuer check failed"
|
|
;;
|
|
84)
|
|
msg="CRITICAL - The FTP PRET command failed"
|
|
;;
|
|
85)
|
|
msg="CRITICAL - RTSP, mismatch of CSeq numbers"
|
|
;;
|
|
86)
|
|
msg="CRITICAL - RTSP, mismatch of Session Identifiers"
|
|
;;
|
|
87)
|
|
msg="CRITICAL - Unable to parse FTP file list"
|
|
;;
|
|
88)
|
|
msg="CRITICAL - FTP chunk callback reported error"
|
|
;;
|
|
89)
|
|
msg="CRITICAL - No connection available, the session will be queued"
|
|
;;
|
|
90)
|
|
msg="CRITICAL - SSL public key does not match pinned public key"
|
|
;;
|
|
91)
|
|
msg="CRITICAL - Invalid SSL certificate status"
|
|
;;
|
|
92)
|
|
msg="CRITICAL - Stream error in HTTP/2 framing layer"
|
|
;;
|
|
93)
|
|
msg="CRITICAL - An API function was called from inside a callback"
|
|
;;
|
|
94)
|
|
msg="CRITICAL - Authentication error"
|
|
;;
|
|
95)
|
|
msg="CRITICAL - HTTP/3 layer error"
|
|
;;
|
|
96)
|
|
msg="CRITICAL - QUIC connection error"
|
|
;;
|
|
97)
|
|
msg="CRITICAL - Proxy handshake error"
|
|
;;
|
|
98)
|
|
msg="CRITICAL - A TLS client certificate is required but was not provided"
|
|
;;
|
|
99)
|
|
msg="CRITICAL - An internal call to poll() or select() returned error that is not recoverable"
|
|
;;
|
|
*)
|
|
echo "UNKNOWN - $CURL_EXIT"
|
|
exit 3
|
|
;;
|
|
esac
|
|
echo "$msg"
|
|
exit 2
|
|
fi
|
|
|
|
RESPONSE_TIME_MS=$(echo "$RESPONSE_TIME * 1000" | bc | xargs printf "%0.0f\n")
|
|
perfdata="response_time=${RESPONSE_TIME_MS}ms;${WARN_TIME};${CRIT_TIME};0;"
|
|
|
|
# Check HTTP code
|
|
if [ -n "$EXPECTED_STATUS_CODE" ]; then
|
|
if [ "$HTTP_CODE" -ne "$EXPECTED_STATUS_CODE" ]; then
|
|
echo "CRITICAL - server returned HTTP code $HTTP_CODE, expected $EXPECTED_STATUS_CODE"
|
|
exit 2
|
|
fi
|
|
elif [ "$IGNORE_STATUS" != "yes" ] && [ "$HTTP_CODE" -ne 200 ]; then
|
|
echo "CRITICAL - server returned HTTP code $HTTP_CODE"
|
|
exit 2
|
|
fi
|
|
|
|
# Check response time
|
|
if [ $(echo "$RESPONSE_TIME_MS > $CRIT_TIME" | bc) -eq 1 ]; then
|
|
echo "CRITICAL - Response time $RESPONSE_TIME seconds | $perfdata"
|
|
exit 2
|
|
elif [ $(echo "$RESPONSE_TIME_MS > $WARN_TIME" | bc) -eq 1 ]; then
|
|
echo "WARNING - response time $RESPONSE_TIME seconds | $perfdata"
|
|
exit 1
|
|
fi
|
|
|
|
# Check critical string
|
|
BODY_CONTAINS=""
|
|
if [ -n "$CRIT_STRING" ]; then
|
|
BODY=$(curl -s $FOLLOW_REDIRECTS $INSECURE "$HEADERS" $RESOLVE $TIMEOUT "$URL")
|
|
# shellcheck disable=SC2076
|
|
if ! [[ $BODY =~ "$CRIT_STRING" ]]; then
|
|
if $SANITIZE_HTML; then
|
|
BODY=$(echo "$BODY" | sed 's/</\</g' | sed 's/>/\>/g')
|
|
fi
|
|
echo "CRITICAL - response body does not contain the required string: $BODY"
|
|
exit 2
|
|
else
|
|
BODY_CONTAINS=" and contained substring"
|
|
fi
|
|
fi
|
|
|
|
# All checks passed
|
|
|
|
if $DISABLE_PERFDATA && [ "$HTTP_CODE" != 200 ]; then
|
|
perfdata_str=""
|
|
else
|
|
perfdata_str="| $perfdata"
|
|
fi
|
|
|
|
echo "OK - response time was $RESPONSE_TIME seconds, code $HTTP_CODE${BODY_CONTAINS}. $perfdata_str"
|
|
exit 0
|