[monitoring-plugins] check_ntp_time: add stratum thresholds (#2357)

GitHub git at monitoring-plugins.org
Tue Sep 29 11:10:14 CEST 2026


    Module: monitoring-plugins
    Branch: master
    Commit: 3b83b31b60931d943467f6ecdd70229a3ceea39b
    Author: Carlos <5107748+Devstellar at users.noreply.github.com>
 Committer: GitHub <noreply at github.com>
      Date: Tue Sep 29 11:07:38 2026 +0200
       URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=3b83b31b

check_ntp_time: add stratum thresholds (#2357)

* check_ntp_time: add stratum thresholds

---------

Co-authored-by: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>

---

 plugins/check_ntp_time.c          | 79 ++++++++++++++++++++++++++++++---------
 plugins/check_ntp_time.d/config.h |  6 +++
 2 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index 75986821..b082b04a 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -320,6 +320,7 @@ static int best_offset_server(const ntp_server_results *slist, int nservers) {
 typedef struct {
 	mp_state_enum offset_result;
 	double offset;
+	int stratum;
 } offset_request_wrapper;
 static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset,
 											 const struct timespec poll_delay) {
@@ -505,6 +506,7 @@ static offset_request_wrapper offset_request(const char *host, const char *port,
 	offset_request_wrapper result = {
 		.offset = 0,
 		.offset_result = STATE_UNKNOWN,
+		.stratum = -1,
 	};
 
 	/* now, pick the best server from the list */
@@ -514,6 +516,8 @@ static offset_request_wrapper offset_request(const char *host, const char *port,
 		result.offset_result = STATE_UNKNOWN;
 	} else {
 		result.offset_result = STATE_OK;
+		result.stratum = servers[best_index].stratum;
+
 		/* finally, calculate the average offset */
 		for (int i = 0; i < servers[best_index].num_responses; i++) {
 			avg_offset += servers[best_index].offset[i];
@@ -542,23 +546,28 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
 	enum {
 		output_format_index = CHAR_MAX + 1,
 		polling_delay_index,
+		stratum_warning_index,
+		stratum_critical_index,
 	};
 
-	static struct option longopts[] = {{"version", no_argument, 0, 'V'},
-									   {"help", no_argument, 0, 'h'},
-									   {"verbose", no_argument, 0, 'v'},
-									   {"use-ipv4", no_argument, 0, '4'},
-									   {"use-ipv6", no_argument, 0, '6'},
-									   {"quiet", no_argument, 0, 'q'},
-									   {"time-offset", required_argument, 0, 'o'},
-									   {"warning", required_argument, 0, 'w'},
-									   {"critical", required_argument, 0, 'c'},
-									   {"timeout", required_argument, 0, 't'},
-									   {"hostname", required_argument, 0, 'H'},
-									   {"port", required_argument, 0, 'p'},
-									   {"poll-delay", required_argument, 0, polling_delay_index},
-									   {"output-format", required_argument, 0, output_format_index},
-									   {0, 0, 0, 0}};
+	static struct option longopts[] = {
+		{"version", no_argument, 0, 'V'},
+		{"help", no_argument, 0, 'h'},
+		{"verbose", no_argument, 0, 'v'},
+		{"use-ipv4", no_argument, 0, '4'},
+		{"use-ipv6", no_argument, 0, '6'},
+		{"quiet", no_argument, 0, 'q'},
+		{"time-offset", required_argument, 0, 'o'},
+		{"warning", required_argument, 0, 'w'},
+		{"critical", required_argument, 0, 'c'},
+		{"stratum-warning", required_argument, 0, stratum_warning_index},
+		{"stratum-critical", required_argument, 0, stratum_critical_index},
+		{"timeout", required_argument, 0, 't'},
+		{"hostname", required_argument, 0, 'H'},
+		{"port", required_argument, 0, 'p'},
+		{"poll-delay", required_argument, 0, polling_delay_index},
+		{"output-format", required_argument, 0, output_format_index},
+		{0, 0, 0, 0}};
 
 	if (argc < 2) {
 		mopl_utils_usage("\n");
@@ -620,6 +629,24 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
 			result.config.offset_thresholds =
 				mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
 		} break;
+		case stratum_warning_index: {
+			result.config.do_stratum = true;
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCESS) {
+				die(STATE_UNKNOWN, "failed to parse warning stratum threshold");
+			}
+			result.config.stratum_thresholds =
+				mp_thresholds_set_warn(result.config.stratum_thresholds, tmp.range);
+		} break;
+		case stratum_critical_index: {
+			result.config.do_stratum = true;
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCESS) {
+				die(STATE_UNKNOWN, "failed to parse critical stratum threshold");
+			}
+			result.config.stratum_thresholds =
+				mp_thresholds_set_crit(result.config.stratum_thresholds, tmp.range);
+		} break;
 		case 'H':
 			if (!mopl_net_is_host(optarg) && (optarg[0] != '/')) {
 				mopl_utils_usage2(_("Invalid hostname/address"), optarg);
@@ -733,6 +760,18 @@ int main(int argc, char *argv[]) {
 	mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
 	mp_add_subcheck_to_check(&overall, sc_offset);
 
+	if (config.do_stratum) {
+		mp_subcheck sc_stratum = mp_subcheck_init();
+		mopl_utils_xasprintf(&sc_stratum.output, "Stratum: %d", offset_result.stratum);
+		mp_perfdata pd_stratum = perfdata_init();
+		pd_stratum = mp_set_pd_value(pd_stratum, offset_result.stratum);
+		pd_stratum = mp_pd_set_thresholds(pd_stratum, config.stratum_thresholds);
+		pd_stratum.label = "stratum";
+		mp_add_perfdata_to_subcheck(&sc_stratum, pd_stratum);
+		sc_stratum = mp_set_subcheck_state(sc_stratum, mp_get_pd_status(pd_stratum));
+		mp_add_subcheck_to_check(&overall, sc_stratum);
+	}
+
 	if (config.server_address != NULL) {
 		free(config.server_address);
 	}
@@ -760,6 +799,10 @@ void print_help(void) {
 	printf("    %s\n", _("Offset to result in warning status (seconds)"));
 	printf(" %s\n", "-c, --critical=THRESHOLD");
 	printf("    %s\n", _("Offset to result in critical status (seconds)"));
+	printf(" %s\n", "--stratum-warning=THRESHOLD");
+	printf("    %s\n", _("Warning threshold for NTP server stratum"));
+	printf(" %s\n", "--stratum-critical=THRESHOLD");
+	printf("    %s\n", _("Critical threshold for NTP server stratum"));
 	printf(" %s\n", "-o, --time-offset=INTEGER");
 	printf("    %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
 	printf(" %s\n", " --poll-delay=DELAY");
@@ -776,7 +819,7 @@ void print_help(void) {
 
 	printf("\n");
 	printf("%s\n", _("Notes:"));
-	printf(" %s\n", _("If you'd rather want to monitor an NTP server, please use"));
+	printf(" %s\n", _("For ntpd-specific peer monitoring, please use"));
 	printf(" %s\n", _("check_ntp_peer."));
 	printf(" %s\n", _("--time-offset is useful for compensating for servers with known"));
 	printf(" %s\n", _("and expected clock skew."));
@@ -792,6 +835,8 @@ void print_help(void) {
 
 void print_usage(void) {
 	printf("%s\n", _("Usage:"));
-	printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n",
+	printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [--stratum-warning <swarn>] "
+		   "[--stratum-critical <scrit>] [-v verbose] "
+		   "[-o <time offset>]\n",
 		   progname);
 }
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h
index 81194a95..c118f487 100644
--- a/plugins/check_ntp_time.d/config.h
+++ b/plugins/check_ntp_time.d/config.h
@@ -19,6 +19,9 @@ typedef struct {
 
 	mp_thresholds offset_thresholds;
 
+	bool do_stratum;
+	mp_thresholds stratum_thresholds;
+
 	bool output_format_is_set;
 	struct timespec poll_delay;
 	mp_output_format output_format;
@@ -34,6 +37,9 @@ check_ntp_time_config check_ntp_time_config_init() {
 
 		.offset_thresholds = mp_thresholds_init(),
 
+		.do_stratum = false,
+		.stratum_thresholds = mp_thresholds_init(),
+
 		.output_format_is_set = false,
 		.poll_delay = default_polling_delay,
 	};



More information about the Commits mailing list