[monitoring-plugins] check_http and check_curl: custom timeout return ...

GitHub git at monitoring-plugins.org
Tue May 19 16:10:13 CEST 2026


    Module: monitoring-plugins
    Branch: master
    Commit: 178e9a02e367ab4527129ddbc623401e245d00b2
    Author: inqrphl <32687873+inqrphl at users.noreply.github.com>
 Committer: GitHub <noreply at github.com>
      Date: Tue May 19 16:01:43 2026 +0200
       URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=178e9a02

check_http and check_curl: custom timeout return state (#2266)

check_curl + check_http:
 hdd cli argument to return custom states on timeout

---------

Co-authored-by: Ahmet Oeztuerk <Ahmet.Oeztuerk at consol.de>

---

 plugins/check_curl.c                      | 35 ++++++++++++++++++++++++++++---
 plugins/check_curl.d/check_curl_helpers.c |  1 +
 plugins/check_curl.d/config.h             |  3 +++
 plugins/check_http.c                      | 25 ++++++++++++++++++++--
 plugins/t/check_curl.t                    | 29 +++++++++++++++++++++++--
 5 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 67d89129..3f44c86b 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -273,9 +273,17 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state
 
 	/* Curl errors, result in critical Nagios state */
 	if (res != CURLE_OK) {
-		xasprintf(&sc_curl.output, _("Error while performing connection: cURL returned %d - %s"),
-				  res, errbuf[0] ? errbuf : curl_easy_strerror(res));
-		sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL);
+		/* Custom handling for timeouts, state might be set to non CRITICAL */
+		if (res == CURLE_OPERATION_TIMEDOUT) {
+			xasprintf(&sc_curl.output, _("cURL returned %d - %s"), res,
+					  errbuf[0] ? errbuf : curl_easy_strerror(res));
+			sc_curl = mp_set_subcheck_state(sc_curl, config.on_timeout_result_state);
+		} else {
+			xasprintf(&sc_curl.output,
+					  _("Error while performing connection: cURL returned %d - %s"), res,
+					  errbuf[0] ? errbuf : curl_easy_strerror(res));
+			sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL);
+		}
 		mp_add_subcheck_to_subcheck(&sc_result, sc_curl);
 		return sc_result;
 	}
@@ -890,6 +898,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
 		STATE_REGEX,
 		OUTPUT_FORMAT,
 		NO_PROXY,
+		TIMEOUT_RESULT,
 	};
 
 	static struct option longopts[] = {
@@ -939,6 +948,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
 		{"cookie-jar", required_argument, 0, COOKIE_JAR},
 		{"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
 		{"output-format", required_argument, 0, OUTPUT_FORMAT},
+		{"timeout-result", required_argument, 0, TIMEOUT_RESULT},
 		{0, 0, 0, 0}};
 
 	check_curl_config_wrapper result = {
@@ -1004,6 +1014,21 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
 				result.config.curl_config.socket_timeout = (int)strtol(optarg, NULL, 10);
 			}
 			break;
+		case TIMEOUT_RESULT:
+			if (!strcmp(optarg, "0") || !strcasecmp(optarg, "ok")) {
+				result.config.on_timeout_result_state = STATE_OK;
+			} else if (!strcmp(optarg, "1") || !strcasecmp(optarg, "warning")) {
+				result.config.on_timeout_result_state = STATE_WARNING;
+			} else if (!strcmp(optarg, "2") || !strcasecmp(optarg, "critical")) {
+				result.config.on_timeout_result_state = STATE_CRITICAL;
+			} else if (!strcmp(optarg, "3") || !strcasecmp(optarg, "unknown")) {
+				result.config.on_timeout_result_state = STATE_UNKNOWN;
+			} else {
+				usage2(_("Invalid timeout-result state option, give either a return code or state "
+						 "name in lowercase"),
+					   optarg);
+			}
+			break;
 		case 'c': /* critical time threshold */
 		{
 			mp_range_parsed critical_range = mp_parse_range_string(optarg);
@@ -1701,6 +1726,10 @@ void print_help(void) {
 
 	printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
 
+	printf(" %s\n", "--timeout-result=ok|warning|critical|unknown|0|1|2|3");
+	printf("    %s\n", _("Timeouts default to returning STATE_CRITICAL."));
+	printf("    %s\n", _("This argument changes the return state on timeouts."));
+
 	printf(UT_VERBOSE);
 
 	printf(UT_OUTPUT_FORMAT);
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c
index 80d6f4f6..5b13a138 100644
--- a/plugins/check_curl.d/check_curl_helpers.c
+++ b/plugins/check_curl.d/check_curl_helpers.c
@@ -755,6 +755,7 @@ check_curl_config check_curl_config_init(void) {
 		.header_expect = "",
 		.on_redirect_result_state = STATE_OK,
 		.on_redirect_dependent = false,
+		.on_timeout_result_state = STATE_CRITICAL,
 
 		.show_extended_perfdata = false,
 		.show_body = false,
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h
index bcdf3010..0a7fa01d 100644
--- a/plugins/check_curl.d/config.h
+++ b/plugins/check_curl.d/config.h
@@ -113,9 +113,12 @@ typedef struct {
 	mp_state_enum on_redirect_result_state;
 	bool on_redirect_dependent;
 
+	mp_state_enum on_timeout_result_state;
+
 	bool show_extended_perfdata;
 	bool show_body;
 
+
 	bool output_format_is_set;
 	mp_output_format output_format;
 } check_curl_config;
diff --git a/plugins/check_http.c b/plugins/check_http.c
index 71f94b91..73e4f3b6 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -205,7 +205,8 @@ bool process_arguments(int argc, char **argv) {
 		SNI_OPTION,
 		MAX_REDIRS_OPTION,
 		CONTINUE_AFTER_CHECK_CERT,
-		STATE_REGEX
+		STATE_REGEX,
+		TIMEOUT_RESULT
 	};
 
 	int option = 0;
@@ -247,6 +248,7 @@ bool process_arguments(int argc, char **argv) {
 		{"extended-perfdata", no_argument, 0, 'E'},
 		{"show-body", no_argument, 0, 'B'},
 		{"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
+		{"timeout-result", required_argument, 0, TIMEOUT_RESULT},
 		{0, 0, 0, 0}};
 
 	if (argc < 2) {
@@ -298,6 +300,21 @@ bool process_arguments(int argc, char **argv) {
 				socket_timeout = atoi(optarg);
 			}
 			break;
+		case TIMEOUT_RESULT:
+			if (!strcmp(optarg, "0") || !strcasecmp(optarg, "ok")) {
+				socket_timeout_state = STATE_OK;
+			} else if (!strcmp(optarg, "1") || !strcasecmp(optarg, "warning")) {
+				socket_timeout_state = STATE_WARNING;
+			} else if (!strcmp(optarg, "2") || !strcasecmp(optarg, "critical")) {
+				socket_timeout_state = STATE_CRITICAL;
+			} else if (!strcmp(optarg, "3") || !strcasecmp(optarg, "unknown")) {
+				socket_timeout_state = STATE_UNKNOWN;
+			} else {
+				usage2(_("Invalid timeout-result state option, give either a return code or state "
+						 "name in lowercase"),
+					   optarg);
+			}
+			break;
 		case 'c': /* critical time threshold */
 			critical_thresholds = optarg;
 			break;
@@ -1032,7 +1049,7 @@ int check_http(void) {
 			printf("SSL initialized\n");
 		}
 		if (result != STATE_OK) {
-			die(STATE_CRITICAL,  _("HTTP CRITICAL - SSL error\n"));
+			die(STATE_CRITICAL, _("HTTP CRITICAL - SSL error\n"));
 		}
 		microsec_ssl = deltime(tv_temp);
 		elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
@@ -1883,6 +1900,10 @@ void print_help(void) {
 
 	printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
 
+	printf(" %s\n", "--timeout-result=ok|warning|critical|unknown|0|1|2|3");
+	printf("    %s\n", _("Timeouts default to returning STATE_CRITICAL."));
+	printf("    %s\n", _("This argument changes the return state on timeouts."));
+
 	printf(UT_VERBOSE);
 
 	printf("\n");
diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t
index 0f4d0de7..7ec8ca06 100644
--- a/plugins/t/check_curl.t
+++ b/plugins/t/check_curl.t
@@ -13,7 +13,7 @@ use vars qw($tests $has_ipv6);
 BEGIN {
     use NPTest;
     $has_ipv6 = NPTest::has_ipv6();
-    $tests = $has_ipv6 ? 57 : 92;
+    $tests = $has_ipv6 ? 65 : 100;
     plan tests => $tests;
 }
 
@@ -69,7 +69,32 @@ $res = NPTest->testCmd(
     );
 cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
 # was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!)
-like( $res->output, "/cURL returned 28 - Connection timed out after/", "Output OK");
+like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK");
+
+# timeout return results can be changed using --timeout-result option
+$res = NPTest->testCmd(
+    "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result ok"
+    );
+like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK");
+cmp_ok( $res->return_code, "==", 0, "Return code is correct due argument: --timeout-result ok");
+
+$res = NPTest->testCmd(
+    "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result warning"
+    );
+like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK");
+cmp_ok( $res->return_code, "==", 1, "Return code is correct due argument: --timeout-result warning");
+
+$res = NPTest->testCmd(
+    "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result 2"
+    );
+like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK");
+cmp_ok( $res->return_code, "==", 2, "Return code is correct due argument: --timeout-result 2");
+
+$res = NPTest->testCmd(
+    "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result 3"
+    );
+like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK");
+cmp_ok( $res->return_code, "==", 3, "Return code is correct due argument: --timeout-result 3");
 
 $res = NPTest->testCmd(
     "./$plugin $hostname_invalid -wt 1 -ct 2"



More information about the Commits mailing list