#!/bin/bash usage() { echo "Usage: $0 -u [-w ] [-c ] [-C ] [-L] [-I] [-H ] [-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. -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) 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" ;; e) EXPECTED_STATUS_CODE="$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" ;; *) 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" != "$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" != 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') 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