icinga2-checks/check_curl.sh

478 lines
11 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 Specify the exact response code that should be returned. Cannot be used with -s option.
-S Sanitize HTML when printing to console. Good for Icinga2 Web.
-n Don't return any perfdata if the status code was not 200.
-a Specify the username and password for authentication in the format username:password"
exit 3
}
# Default values
WARN_TIME=700
CRIT_TIME=1000
FOLLOW_REDIRECTS=""
INSECURE=""
HEADERS=""
PRINT_CURL=""
RESOLVE=""
IGNORE_STATUS=""
TIMEOUT="--max-time 30"
HTTP_METHOD="-X GET"
EXPECTED_STATUS_CODE=""
SANITIZE_HTML=false
DISABLE_PERFDATA=false
AUTHENTICATION=""
# Parse arguments
while getopts "u:w:c:C:LH:M:IpR:st:e:hSna:" 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)
if [ -n "$EXPECTED_STATUS_CODE" ]; then
echo "Cannot use -s option with -e option"
exit 3
fi
IGNORE_STATUS="yes"
;;
t)
TIMEOUT="--max-time $OPTARG"
;;
M)
HTTP_METHOD="-X $OPTARG"
;;
h)
usage
;;
S)
SANITIZE_HTML=true
;;
n)
DISABLE_PERFDATA=true
;;
e)
if [ "$IGNORE_STATUS" = "yes" ]; then
echo "Cannot use -e option with -s option"
exit 3
fi
EXPECTED_STATUS_CODE="$OPTARG"
;;
a)
AUTHENTICATION="--user $OPTARG"
;;
*)
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 $AUTHENTICATION $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;"
EXIT_CODE=0
ERROR_MSG=""
# Check HTTP code
if [ -n "$EXPECTED_STATUS_CODE" ]; then
if [ "$HTTP_CODE" != "$EXPECTED_STATUS_CODE" ]; then
STATUS_CODE_MSG="server returned HTTP code $HTTP_CODE, expected $EXPECTED_STATUS_CODE"
ERROR_MSG="${ERROR_MSG}${STATUS_CODE_MSG}; "
EXIT_CODE=2
fi
elif [ "$IGNORE_STATUS" != "yes" ] && [ "$HTTP_CODE" != 200 ]; then
STATUS_CODE_MSG="server returned HTTP code $HTTP_CODE"
ERROR_MSG="${ERROR_MSG}${STATUS_CODE_MSG}; "
EXIT_CODE=2
fi
# Check response time
if [ "$(echo "$RESPONSE_TIME_MS > $CRIT_TIME" | bc)" -eq 1 ]; then
RESPONSE_TIME_MSG="Response time $RESPONSE_TIME seconds exceeded critical threshold"
ERROR_MSG="${ERROR_MSG}${RESPONSE_TIME_MSG}; "
EXIT_CODE=2
elif [ "$(echo "$RESPONSE_TIME_MS > $WARN_TIME" | bc)" -eq 1 ]; then
RESPONSE_TIME_MSG="Response time $RESPONSE_TIME seconds exceeded warning threshold"
ERROR_MSG="${ERROR_MSG}${RESPONSE_TIME_MSG}; "
if [ $EXIT_CODE -lt 1 ]; then
EXIT_CODE=1
fi
fi
# Check critical string
BODY_CONTAINS=""
if [ -n "$CRIT_STRING" ]; then
BODY=$(curl -s $FOLLOW_REDIRECTS $INSECURE $HEADERS $RESOLVE $TIMEOUT $AUTHENTICATION "$URL")
if ! echo "$BODY" | grep -Fq "$CRIT_STRING"; then
if $SANITIZE_HTML; then
BODY=$(echo "$BODY" | sed 's/</\&lt;/g' | sed 's/>/\&gt;/g')
fi
CRIT_STRING_MSG="response body does not contain the required string"
ERROR_MSG="${ERROR_MSG}${CRIT_STRING_MSG}; "
EXIT_CODE=2
else
BODY_CONTAINS=", and contained substring"
fi
fi
# Prepare perfdata_str
if $DISABLE_PERFDATA && [ "$HTTP_CODE" != 200 ]; then
perfdata_str=""
else
perfdata_str="| $perfdata"
fi
# Remove trailing spaces and the `;` char from the message.
ERROR_MSG=$(echo "$ERROR_MSG" | xargs | sed 's/;*$//g')
# Output result
if [ $EXIT_CODE -eq 0 ]; then
echo "OK - response time was $RESPONSE_TIME seconds, code $HTTP_CODE${BODY_CONTAINS} $perfdata_str"
exit 0
elif [ $EXIT_CODE -eq 1 ]; then
echo "WARNING - $ERROR_MSG $perfdata_str"
exit 1
else
echo "CRITICAL - $ERROR_MSG $perfdata_str"
exit 2
fi