Merge branch 'master' into remove/check_ntp

This commit is contained in:
Lorenz Kästle 2025-12-04 00:32:30 +01:00
commit be86e3ef5a
11 changed files with 283 additions and 960 deletions

View file

@ -652,19 +652,6 @@ Provides check_nagios of the Monitoring Plugins.
# check_nt
%package nt
Summary: Monitoring Plugins - check_nt
Requires: %{name} = %{version}-%{release}
%description nt
Provides check_nt of the Monitoring Plugins.
%files nt
%{plugindir}/check_nt
# check_ntp_peer
%package ntp_peer
Summary: Monitoring Plugins - check_ntp_peer

1
.gitignore vendored
View file

@ -174,7 +174,6 @@ plugins/check_disk.d/.dirstamp
/plugins/check_netsaint
/plugins/check_nntp
/plugins/check_nntps
/plugins/check_nt
/plugins/check_ntp_peer
/plugins/check_ntp_time
/plugins/check_pgsql

View file

@ -26,7 +26,7 @@ check_curl:
other SSL implementations are currently not supported
- uriparser 0.7.5 or later
https://uriparser.github.io/
check_fping:
- Requires the fping utility distributed with SATAN. Either
download and install SATAN or grab the fping program from
@ -87,16 +87,12 @@ check_ifstatus/check_ifoperstatus
- Requires Net::SNMP perl module
http://www.perl.com/CPAN/modules/by-authors/id/D/DT/DTOWN/
check_nt:
- Requires NSClient to run on the NT server to monitor
http://nsclient.ready2run.nl/
check_ups:
- Requires Network UPS Tools (>= 1.4) to run on the server to monitor
http://www.networkupstools.org/
check_ide_smart:
- Uses the Linux specific SMART interface [http://smartlinux.sourceforge.net/smart/index.php].
- Uses the Linux specific SMART interface [http://smartlinux.sourceforge.net/smart/index.php].
OS Specific Issues
------------------

View file

@ -1832,11 +1832,6 @@ if test -n "$PATH_TO_APTGET" ; then
fi
if test -f $srcdir/plugins/check_nt.c ; then
EXTRAS="$EXTRAS check_nt\$(EXEEXT)"
fi
dnl used in check_dhcp
AC_CHECK_HEADERS(sys/sockio.h)

View file

@ -44,7 +44,7 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \
EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \
check_swap check_fping check_ldap check_game check_dig \
check_nagios check_by_ssh check_dns check_nt check_ide_smart \
check_nagios check_by_ssh check_dns check_ide_smart \
check_procs check_mysql_query check_apt check_dbi check_curl \
\
tests/test_check_swap \
@ -76,7 +76,6 @@ EXTRA_DIST = t \
check_tcp.d \
check_real.d \
check_ssh.d \
check_nt.d \
check_dns.d \
check_mrtgtraf.d \
check_mysql_query.d \
@ -157,7 +156,6 @@ check_mysql_query_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
check_nagios_LDADD = $(BASEOBJS)
check_nt_LDADD = $(NETLIBS)
check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
check_ping_LDADD = $(NETLIBS)

View file

@ -3,7 +3,7 @@
* Monitoring check_dig plugin
*
* License: GPL
* Copyright (c) 2002-2024 Monitoring Plugins Development Team
* Copyright (c) 2002-2025 Monitoring Plugins Development Team
*
* Description:
*
@ -33,9 +33,10 @@
* because on some architectures those strings are in non-writable memory */
const char *progname = "check_dig";
const char *copyright = "2002-2024";
const char *copyright = "2002-2025";
const char *email = "devel@monitoring-plugins.org";
#include <ctype.h>
#include "common.h"
#include "netutils.h"
#include "utils.h"
@ -56,6 +57,12 @@ void print_usage(void);
static int verbose = 0;
/* helpers for flag parsing */
static flag_list parse_flags_line(const char *line);
static flag_list split_csv_trim(const char *csv);
static bool flag_list_contains(const flag_list *list, const char *needle);
static void free_flag_list(flag_list *list);
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@ -101,13 +108,35 @@ int main(int argc, char **argv) {
output chld_out;
output chld_err;
char *msg = NULL;
flag_list dig_flags = {.items = NULL, .count = 0};
mp_state_enum result = STATE_UNKNOWN;
/* run the command */
if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
result = STATE_WARNING;
msg = (char *)_("dig returned an error status");
}
/* extract ';; flags: ...' from stdout (first occurrence) */
for (size_t i = 0; i < chld_out.lines; i++) {
if (strstr(chld_out.line[i], "flags:")) {
if (verbose) {
printf("Raw flags line: %s\n", chld_out.line[i]);
}
dig_flags = parse_flags_line(chld_out.line[i]);
if (verbose && dig_flags.count > 0) {
printf(_("Parsed flags:"));
for (size_t k = 0; k < dig_flags.count; k++) {
printf(" %s", dig_flags.items[k]);
}
printf("\n");
}
break;
}
}
for (size_t i = 0; i < chld_out.lines; i++) {
/* the server is responding, we just got the host name... */
if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
@ -174,6 +203,44 @@ int main(int argc, char **argv) {
result = STATE_WARNING;
}
/* Optional: evaluate dig flags only if -E/-X were provided */
if ((config.require_flags.count > 0) || (config.forbid_flags.count > 0)) {
if (dig_flags.count > 0) {
for (size_t r = 0; r < config.require_flags.count; r++) {
if (!flag_list_contains(&dig_flags, config.require_flags.items[r])) {
result = STATE_CRITICAL;
if (!msg) {
xasprintf(&msg, _("Missing required DNS flag: %s"),
config.require_flags.items[r]);
} else {
char *newmsg = NULL;
xasprintf(&newmsg, _("%s; missing required DNS flag: %s"), msg,
config.require_flags.items[r]);
msg = newmsg;
}
}
}
for (size_t r = 0; r < config.forbid_flags.count; r++) {
if (flag_list_contains(&dig_flags, config.forbid_flags.items[r])) {
result = STATE_CRITICAL;
if (!msg) {
xasprintf(&msg, _("Forbidden DNS flag present: %s"),
config.forbid_flags.items[r]);
} else {
char *newmsg = NULL;
xasprintf(&newmsg, _("%s; forbidden DNS flag present: %s"), msg,
config.forbid_flags.items[r]);
msg = newmsg;
}
}
}
}
}
/* cleanup flags buffer */
free_flag_list(&dig_flags);
printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
msg ? msg : _("Probably a non-existent host/domain"),
fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED),
@ -190,6 +257,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
{"critical", required_argument, 0, 'c'},
{"timeout", required_argument, 0, 't'},
{"dig-arguments", required_argument, 0, 'A'},
{"require-flags", required_argument, 0, 'E'},
{"forbid-flags", required_argument, 0, 'X'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
@ -212,7 +281,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
int option_index =
getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:E:X:46", longopts, &option);
if (option_index == -1 || option_index == EOF) {
break;
@ -263,6 +333,12 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) {
case 'A': /* dig arguments */
result.config.dig_args = strdup(optarg);
break;
case 'E': /* require flags */
result.config.require_flags = split_csv_trim(optarg);
break;
case 'X': /* forbid flags */
result.config.forbid_flags = split_csv_trim(optarg);
break;
case 'v': /* verbose */
verbose++;
break;
@ -343,6 +419,10 @@ void print_help(void) {
printf(" %s\n", _("was in -l"));
printf(" %s\n", "-A, --dig-arguments=STRING");
printf(" %s\n", _("Pass STRING as argument(s) to dig"));
printf(" %s\n", "-E, --require-flags=LIST");
printf(" %s\n", _("Comma-separated dig flags that must be present (e.g. 'aa,qr')"));
printf(" %s\n", "-X, --forbid-flags=LIST");
printf(" %s\n", _("Comma-separated dig flags that must NOT be present"));
printf(UT_WARN_CRIT);
printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
printf(UT_VERBOSE);
@ -359,5 +439,185 @@ void print_usage(void) {
printf("%s\n", _("Usage:"));
printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
printf(" [-t <timeout>] [-a <expected answer address>] [-v]\n");
printf(" [-t <timeout>] [-a <expected answer address>] [-E <flags>] [-X <flags>] [-v]\n");
}
/* helpers */
/**
* parse_flags_line - Parse a dig output line and extract DNS header flags.
*
* Input:
* line - NUL terminated dig output line, e.g. ";; flags: qr rd ra; ..."
*
* Returns:
* flag_list where:
* - items: array of NUL terminated flag strings (heap allocated)
* - count: number of entries in items
* On parse failure or if no flags were found, count is 0 and items is NULL.
*/
static flag_list parse_flags_line(const char *line) {
flag_list result = {.items = NULL, .count = 0};
if (!line) {
return result;
}
/* Locate start of DNS header flags in dig output */
const char *p = strstr(line, "flags:");
if (!p) {
return result;
}
p += 6; /* skip literal "flags:" */
/* Skip whitespace after "flags:" */
while (*p && isspace((unsigned char)*p)) {
p++;
}
/* Flags are terminated by the next semicolon e.g. "qr rd ra;" */
const char *q = strchr(p, ';');
if (!q) {
return result;
}
/* Extract substring containing the flag block */
size_t len = (size_t)(q - p);
if (len == 0) {
return result;
}
char *buf = (char *)malloc(len + 1);
if (!buf) {
return result;
}
memcpy(buf, p, len);
buf[len] = '\0';
/* Tokenize flags separated by whitespace */
char **arr = NULL;
size_t cnt = 0;
char *saveptr = NULL;
char *tok = strtok_r(buf, " \t", &saveptr);
while (tok) {
/* Expand array for the next flag token */
char **tmp = (char **)realloc(arr, (cnt + 1) * sizeof(char *));
if (!tmp) {
/* On allocation failure keep what we have and return it */
break;
}
arr = tmp;
arr[cnt++] = strdup(tok);
tok = strtok_r(NULL, " \t", &saveptr);
}
free(buf);
result.items = arr;
result.count = cnt;
return result;
}
/**
* split_csv_trim - Split a comma separated string into trimmed tokens.
*
* Input:
* csv - NUL terminated string, e.g. "aa, qr , rd"
*
* Returns:
* flag_list where:
* - items: array of NUL terminated tokens (heap allocated, whitespace trimmed)
* - count: number of tokens
* On empty input, count is 0 and items is NULL
*/
static flag_list split_csv_trim(const char *csv) {
flag_list result = {.items = NULL, .count = 0};
if (!csv || !*csv) {
return result;
}
char *tmp = strdup(csv);
if (!tmp) {
return result;
}
char *s = tmp;
char *token = NULL;
/* Split CSV by commas, trimming whitespace on each token */
while ((token = strsep(&s, ",")) != NULL) {
/* trim leading whitespace */
while (*token && isspace((unsigned char)*token)) {
token++;
}
/* trim trailing whitespace */
char *end = token + strlen(token);
while (end > token && isspace((unsigned char)end[-1])) {
*--end = '\0';
}
if (*token) {
/* Expand the items array and append the token */
char **arr = (char **)realloc(result.items, (result.count + 1) * sizeof(char *));
if (!arr) {
/* Allocation failed, stop and return what we have */
break;
}
result.items = arr;
result.items[result.count++] = strdup(token);
}
}
free(tmp);
return result;
}
/**
* flag_list_contains - Case-insensitive membership test in a flag_list.
*
* Input:
* list - pointer to a flag_list
* needle - NUL terminated string to search for
*
* Returns:
* true if needle is contained in list (strcasecmp)
* false otherwise
*/
static bool flag_list_contains(const flag_list *list, const char *needle) {
if (!list || !needle || !*needle) {
return false;
}
for (size_t i = 0; i < list->count; i++) {
if (strcasecmp(list->items[i], needle) == 0) {
return true;
}
}
return false;
}
/**
* free_flag_list - Release all heap allocations held by a flag_list.
*
* Input:
* list - pointer to a flag_list whose items were allocated by
* parse_flags_line() or split_csv_trim().
*
* After this call list->items is NULL and list->count is 0.
*/
static void free_flag_list(flag_list *list) {
if (!list || !list->items) {
return;
}
for (size_t i = 0; i < list->count; i++) {
free(list->items[i]);
}
free(list->items);
list->items = NULL;
list->count = 0;
}

View file

@ -7,6 +7,11 @@
#define DEFAULT_PORT 53
#define DEFAULT_TRIES 2
typedef struct {
char **items;
size_t count;
} flag_list;
typedef struct {
char *query_address;
char *record_type;
@ -19,6 +24,8 @@ typedef struct {
double warning_interval;
double critical_interval;
flag_list require_flags;
flag_list forbid_flags;
} check_dig_config;
check_dig_config check_dig_config_init() {
@ -34,7 +41,8 @@ check_dig_config check_dig_config_init() {
.warning_interval = UNDEFINED,
.critical_interval = UNDEFINED,
.require_flags = {.count = 0, .items = NULL},
.forbid_flags = {.count = 0, .items = NULL},
};
return tmp;
}

View file

@ -1,789 +0,0 @@
/*****************************************************************************
*
* Monitoring check_nt plugin
*
* License: GPL
* Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com)
* Copyright (c) 2003-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_nt plugin
*
* This plugin collects data from the NSClient service running on a
* Windows NT/2000/XP/2003 server.
* This plugin requires NSClient software to run on NT
* (https://nsclient.org/)
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
const char *progname = "check_nt";
const char *copyright = "2000-2024";
const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
#include "check_nt.d/config.h"
enum {
MAX_VALUE_LIST = 30,
};
static char recv_buffer[MAX_INPUT_BUFFER];
static void fetch_data(const char *address, int port, const char *sendb);
typedef struct {
int errorcode;
check_nt_config config;
} check_nt_config_wrapper;
static check_nt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void preparelist(char *string);
static bool strtoularray(unsigned long *array, char *string, const char *delim);
static void print_help(void);
void print_usage(void);
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
check_nt_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_nt_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
/* set socket timeout */
alarm(socket_timeout);
int return_code = STATE_UNKNOWN;
char *send_buffer = NULL;
char *output_message = NULL;
char *perfdata = NULL;
char *temp_string = NULL;
char *temp_string_perf = NULL;
char *description = NULL;
char *counter_unit = NULL;
char *errcvt = NULL;
unsigned long lvalue_list[MAX_VALUE_LIST];
switch (config.vars_to_check) {
case CHECK_CLIENTVERSION:
xasprintf(&send_buffer, "%s&1", config.req_password);
fetch_data(config.server_address, config.server_port, send_buffer);
if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) {
xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"),
recv_buffer, config.value_list);
return_code = STATE_WARNING;
} else {
xasprintf(&output_message, "%s", recv_buffer);
return_code = STATE_OK;
}
break;
case CHECK_CPULOAD:
if (config.value_list == NULL) {
output_message = strdup(_("missing -l parameters"));
} else if (!strtoularray(lvalue_list, config.value_list, ",")) {
output_message = strdup(_("wrong -l parameter."));
} else {
/* -l parameters is present with only integers */
return_code = STATE_OK;
temp_string = strdup(_("CPU Load"));
temp_string_perf = strdup(" ");
/* loop until one of the parameters is wrong or not present */
int offset = 0;
while (lvalue_list[0 + offset] > (unsigned long)0 &&
lvalue_list[0 + offset] <= (unsigned long)17280 &&
lvalue_list[1 + offset] > (unsigned long)0 &&
lvalue_list[1 + offset] <= (unsigned long)100 &&
lvalue_list[2 + offset] > (unsigned long)0 &&
lvalue_list[2 + offset] <= (unsigned long)100) {
/* Send request and retrieve data */
xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]);
fetch_data(config.server_address, config.server_port, send_buffer);
unsigned long utilization = strtoul(recv_buffer, NULL, 10);
/* Check if any of the request is in a warning or critical state */
if (utilization >= lvalue_list[2 + offset]) {
return_code = STATE_CRITICAL;
} else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
return_code = STATE_WARNING;
}
xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization,
lvalue_list[0 + offset]);
xasprintf(&temp_string, "%s%s", temp_string, output_message);
xasprintf(&perfdata, _(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"),
lvalue_list[0 + offset], utilization, lvalue_list[1 + offset],
lvalue_list[2 + offset]);
xasprintf(&temp_string_perf, "%s%s", temp_string_perf, perfdata);
offset += 3; /* move across the array */
}
if (strlen(temp_string) > 10) { /* we had at least one loop */
output_message = strdup(temp_string);
perfdata = temp_string_perf;
} else {
output_message = strdup(_("not enough values for -l parameters"));
}
}
break;
case CHECK_UPTIME: {
char *tmp_value_list = config.value_list;
if (config.value_list == NULL) {
tmp_value_list = "minutes";
}
if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) &&
strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
strncmp(config.value_list, "hours", strlen("hours") + 1) &&
strncmp(tmp_value_list, "days", strlen("days") + 1)) {
output_message = strdup(_("wrong -l argument"));
} else {
xasprintf(&send_buffer, "%s&3", config.req_password);
fetch_data(config.server_address, config.server_port, send_buffer);
unsigned long uptime = strtoul(recv_buffer, NULL, 10);
int updays = uptime / 86400;
int uphours = (uptime % 86400) / 3600;
int upminutes = ((uptime % 86400) % 3600) / 60;
if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
uptime = uptime / 60;
} else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
uptime = uptime / 3600;
} else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
uptime = uptime / 86400;
}
/* else uptime in seconds, nothing to do */
xasprintf(&output_message,
_("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays,
uphours, upminutes, uptime);
if (config.check_critical_value && uptime <= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value && uptime <= config.warning_value) {
return_code = STATE_WARNING;
} else {
return_code = STATE_OK;
}
}
} break;
case CHECK_USEDDISKSPACE:
if (config.value_list == NULL) {
output_message = strdup(_("missing -l parameters"));
} else if (strlen(config.value_list) != 1) {
output_message = strdup(_("wrong -l argument"));
} else {
xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
char *fds = strtok(recv_buffer, "&");
char *tds = strtok(NULL, "&");
double total_disk_space = 0;
double free_disk_space = 0;
if (fds != NULL) {
free_disk_space = atof(fds);
}
if (tds != NULL) {
total_disk_space = atof(tds);
}
if (total_disk_space > 0 && free_disk_space >= 0) {
double percent_used_space =
((total_disk_space - free_disk_space) / total_disk_space) * 100;
double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
double critical_used_space =
((float)config.critical_value / 100) * total_disk_space;
xasprintf(
&temp_string,
_("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"),
config.value_list, total_disk_space / 1073741824,
(total_disk_space - free_disk_space) / 1073741824, percent_used_space,
free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"),
config.value_list, (total_disk_space - free_disk_space) / 1073741824,
warning_used_space / 1073741824, critical_used_space / 1073741824,
total_disk_space / 1073741824);
if (config.check_critical_value && percent_used_space >= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value &&
percent_used_space >= config.warning_value) {
return_code = STATE_WARNING;
} else {
return_code = STATE_OK;
}
output_message = strdup(temp_string);
perfdata = temp_string_perf;
} else {
output_message = strdup(_("Free disk space : Invalid drive"));
return_code = STATE_UNKNOWN;
}
}
break;
case CHECK_SERVICESTATE:
case CHECK_PROCSTATE:
if (config.value_list == NULL) {
output_message = strdup(_("No service/process specified"));
} else {
preparelist(
config.value_list); /* replace , between services with & to send the request */
xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password,
(config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
(config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
char *numstr = strtok(recv_buffer, "&");
if (numstr == NULL) {
die(STATE_UNKNOWN, _("could not fetch information from server\n"));
}
return_code = atoi(numstr);
temp_string = strtok(NULL, "&");
output_message = strdup(temp_string);
}
break;
case CHECK_MEMUSE:
xasprintf(&send_buffer, "%s&7", config.req_password);
fetch_data(config.server_address, config.server_port, send_buffer);
char *numstr = strtok(recv_buffer, "&");
if (numstr == NULL) {
die(STATE_UNKNOWN, _("could not fetch information from server\n"));
}
double mem_commitLimit = atof(numstr);
numstr = strtok(NULL, "&");
if (numstr == NULL) {
die(STATE_UNKNOWN, _("could not fetch information from server\n"));
}
double mem_commitByte = atof(numstr);
double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit;
double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit;
/* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
which equals RAM + Pagefiles. */
xasprintf(
&output_message,
_("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space,
(mem_commitLimit - mem_commitByte) / 1048567,
(mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
xasprintf(&perfdata, _("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"),
mem_commitByte / 1048567, warning_used_space / 1048567,
critical_used_space / 1048567, mem_commitLimit / 1048567);
return_code = STATE_OK;
if (config.check_critical_value && percent_used_space >= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value && percent_used_space >= config.warning_value) {
return_code = STATE_WARNING;
}
break;
case CHECK_COUNTER: {
/*
CHECK_COUNTER has been modified to provide extensive perfdata information.
In order to do this, some modifications have been done to the code
and some constraints have been introduced.
1) For the sake of simplicity of the code, perfdata information will only be
provided when the "description" field is added.
2) If the counter you're going to measure is percent-based, the code will detect
the percent sign in its name and will attribute minimum (0%) and maximum (100%)
values automagically, as well the "%" sign to graph units.
3) OTOH, if the counter is "absolute", you'll have to provide the following
the counter unit - that is, the dimensions of the counter you're getting. Examples:
pages/s, packets transferred, etc.
4) If you want, you may provide the minimum and maximum values to expect. They aren't
mandatory, but once specified they MUST have the same order of magnitude and units of -w and
-c; otherwise. strange things will happen when you make graphs of your data.
*/
double counter_value = 0.0;
if (config.value_list == NULL) {
output_message = strdup(_("No counter specified"));
} else {
preparelist(
config.value_list); /* replace , between services with & to send the request */
bool isPercent = (strchr(config.value_list, '%') != NULL);
strtok(config.value_list, "&"); /* burn the first parameters */
description = strtok(NULL, "&");
counter_unit = strtok(NULL, "&");
xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
counter_value = atof(recv_buffer);
bool allRight = false;
if (description == NULL) {
xasprintf(&output_message, "%.f", counter_value);
} else if (isPercent) {
counter_unit = strdup("%");
allRight = true;
}
char *minval = NULL;
char *maxval = NULL;
double fminval = 0;
double fmaxval = 0;
if ((counter_unit != NULL) && (!allRight)) {
minval = strtok(NULL, "&");
maxval = strtok(NULL, "&");
/* All parameters specified. Let's check the numbers */
fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1;
if ((fminval == 0) && (minval == errcvt)) {
output_message = strdup(_("Minimum value contains non-numbers"));
} else {
if ((fmaxval == 0) && (maxval == errcvt)) {
output_message = strdup(_("Maximum value contains non-numbers"));
} else {
allRight = true; /* Everything is OK. */
}
}
} else if ((counter_unit == NULL) && (description != NULL)) {
output_message = strdup(_("No unit counter specified"));
}
if (allRight) {
/* Let's format the output string, finally... */
if (strstr(description, "%") == NULL) {
xasprintf(&output_message, "%s = %.2f %s", description, counter_value,
counter_unit);
} else {
/* has formatting, will segv if wrong */
xasprintf(&output_message, description, counter_value);
}
xasprintf(&output_message, "%s |", output_message);
xasprintf(&output_message, "%s %s", output_message,
fperfdata(description, counter_value, counter_unit, 1,
config.warning_value, 1, config.critical_value,
(!(isPercent) && (minval != NULL)), fminval,
(!(isPercent) && (minval != NULL)), fmaxval));
}
}
if (config.critical_value > config.warning_value) { /* Normal thresholds */
if (config.check_critical_value && counter_value >= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value && counter_value >= config.warning_value) {
return_code = STATE_WARNING;
} else {
return_code = STATE_OK;
}
} else { /* inverse thresholds */
return_code = STATE_OK;
if (config.check_critical_value && counter_value <= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value && counter_value <= config.warning_value) {
return_code = STATE_WARNING;
}
}
} break;
case CHECK_FILEAGE:
if (config.value_list == NULL) {
output_message = strdup(_("No counter specified"));
} else {
preparelist(
config.value_list); /* replace , between services with & to send the request */
xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
description = strtok(NULL, "&");
output_message = strdup(description);
if (config.critical_value > config.warning_value) { /* Normal thresholds */
if (config.check_critical_value && age_in_minutes >= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
return_code = STATE_WARNING;
} else {
return_code = STATE_OK;
}
} else { /* inverse thresholds */
if (config.check_critical_value && age_in_minutes <= config.critical_value) {
return_code = STATE_CRITICAL;
} else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
return_code = STATE_WARNING;
} else {
return_code = STATE_OK;
}
}
}
break;
case CHECK_INSTANCES:
if (config.value_list == NULL) {
output_message = strdup(_("No counter specified"));
} else {
xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
if (!strncmp(recv_buffer, "ERROR", 5)) {
printf("NSClient - %s\n", recv_buffer);
exit(STATE_UNKNOWN);
}
xasprintf(&output_message, "%s", recv_buffer);
return_code = STATE_OK;
}
break;
case CHECK_NONE:
default:
usage4(_("Please specify a variable to check"));
break;
}
/* reset timeout */
alarm(0);
if (perfdata == NULL) {
printf("%s\n", output_message);
} else {
printf("%s | %s\n", output_message, perfdata);
}
return return_code;
}
/* process command-line arguments */
check_nt_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"port", required_argument, 0, 'p'},
{"timeout", required_argument, 0, 't'},
{"critical", required_argument, 0, 'c'},
{"warning", required_argument, 0, 'w'},
{"variable", required_argument, 0, 'v'},
{"hostname", required_argument, 0, 'H'},
{"params", required_argument, 0, 'l'},
{"secret", required_argument, 0, 's'},
{"display", required_argument, 0, 'd'},
{"unknown-timeout", no_argument, 0, 'u'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
check_nt_config_wrapper result = {
.errorcode = OK,
.config = check_nt_config_init(),
};
/* no options were supplied */
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
/* backwards compatibility */
if (!is_option(argv[1])) {
result.config.server_address = strdup(argv[1]);
argv[1] = argv[0];
argv = &argv[1];
argc--;
}
for (int index = 1; index < argc; index++) {
if (strcmp("-to", argv[index]) == 0) {
strcpy(argv[index], "-t");
} else if (strcmp("-wv", argv[index]) == 0) {
strcpy(argv[index], "-w");
} else if (strcmp("-cv", argv[index]) == 0) {
strcpy(argv[index], "-c");
}
}
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
if (option_index == -1 || option_index == EOF || option_index == 1) {
break;
}
switch (option_index) {
case '?': /* print short usage statement if args not parsable */
usage5();
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'H': /* hostname */
result.config.server_address = optarg;
break;
case 's': /* password */
result.config.req_password = optarg;
break;
case 'p': /* port */
if (is_intnonneg(optarg)) {
result.config.server_port = atoi(optarg);
} else {
die(STATE_UNKNOWN, _("Server port must be an integer\n"));
}
break;
case 'v':
if (strlen(optarg) < 4) {
result.errorcode = ERROR;
return result;
}
if (!strcmp(optarg, "CLIENTVERSION")) {
result.config.vars_to_check = CHECK_CLIENTVERSION;
} else if (!strcmp(optarg, "CPULOAD")) {
result.config.vars_to_check = CHECK_CPULOAD;
} else if (!strcmp(optarg, "UPTIME")) {
result.config.vars_to_check = CHECK_UPTIME;
} else if (!strcmp(optarg, "USEDDISKSPACE")) {
result.config.vars_to_check = CHECK_USEDDISKSPACE;
} else if (!strcmp(optarg, "SERVICESTATE")) {
result.config.vars_to_check = CHECK_SERVICESTATE;
} else if (!strcmp(optarg, "PROCSTATE")) {
result.config.vars_to_check = CHECK_PROCSTATE;
} else if (!strcmp(optarg, "MEMUSE")) {
result.config.vars_to_check = CHECK_MEMUSE;
} else if (!strcmp(optarg, "COUNTER")) {
result.config.vars_to_check = CHECK_COUNTER;
} else if (!strcmp(optarg, "FILEAGE")) {
result.config.vars_to_check = CHECK_FILEAGE;
} else if (!strcmp(optarg, "INSTANCES")) {
result.config.vars_to_check = CHECK_INSTANCES;
} else {
result.errorcode = ERROR;
return result;
}
break;
case 'l': /* value list */
result.config.value_list = optarg;
break;
case 'w': /* warning threshold */
result.config.warning_value = strtoul(optarg, NULL, 10);
result.config.check_warning_value = true;
break;
case 'c': /* critical threshold */
result.config.critical_value = strtoul(optarg, NULL, 10);
result.config.check_critical_value = true;
break;
case 'd': /* Display select for services */
if (!strcmp(optarg, "SHOWALL")) {
result.config.show_all = true;
}
break;
case 'u':
socket_timeout_state = STATE_UNKNOWN;
break;
case 't': /* timeout */
socket_timeout = atoi(optarg);
if (socket_timeout <= 0) {
result.errorcode = ERROR;
return result;
}
}
}
if (result.config.server_address == NULL) {
usage4(_("You must provide a server address or host name"));
}
if (result.config.vars_to_check == CHECK_NONE) {
result.errorcode = ERROR;
return result;
}
if (result.config.req_password == NULL) {
result.config.req_password = strdup(_("None"));
}
return result;
}
void fetch_data(const char *address, int port, const char *sendb) {
int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
if (result != STATE_OK) {
die(result, _("could not fetch information from server\n"));
}
if (!strncmp(recv_buffer, "ERROR", 5)) {
die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
}
}
bool strtoularray(unsigned long *array, char *string, const char *delim) {
/* split a <delim> delimited string into a long array */
for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
array[idx] = 0;
}
int idx = 0;
for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
array[idx] = strtoul(t1, NULL, 10);
idx++;
} else {
return false;
}
}
return true;
}
void preparelist(char *string) {
/* Replace all , with & which is the delimiter for the request */
for (int i = 0; (size_t)i < strlen(string); i++) {
if (string[i] == ',') {
string[i] = '&';
}
}
}
void print_help(void) {
print_revision(progname, NP_VERSION);
printf("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n");
printf(COPYRIGHT, copyright, email);
printf("%s\n", _("This plugin collects data from the NSClient service running on a"));
printf("%s\n", _("Windows NT/2000/XP/2003 server."));
printf("\n\n");
print_usage();
printf(UT_HELP_VRSN);
printf(UT_EXTRA_OPTS);
printf("%s\n", _("Options:"));
printf(" %s\n", "-H, --hostname=HOST");
printf(" %s\n", _("Name of the host to check"));
printf(" %s\n", "-p, --port=INTEGER");
printf(" %s", _("Optional port number (default: "));
printf("%d)\n", PORT);
printf(" %s\n", "-s, --secret=<password>");
printf(" %s\n", _("Password needed for the request"));
printf(" %s\n", "-w, --warning=INTEGER");
printf(" %s\n", _("Threshold which will result in a warning status"));
printf(" %s\n", "-c, --critical=INTEGER");
printf(" %s\n", _("Threshold which will result in a critical status"));
printf(" %s\n", "-t, --timeout=INTEGER");
printf(" %s", _("Seconds before connection attempt times out (default: "));
printf(" %s\n", "-l, --params=<parameters>");
printf(" %s", _("Parameters passed to specified check (see below)"));
printf(" %s\n", "-d, --display={SHOWALL}");
printf(" %s", _("Display options (currently only SHOWALL works)"));
printf(" %s\n", "-u, --unknown-timeout");
printf(" %s", _("Return UNKNOWN on timeouts"));
printf("%d)\n", DEFAULT_SOCKET_TIMEOUT);
printf(" %s\n", "-h, --help");
printf(" %s\n", _("Print this help screen"));
printf(" %s\n", "-V, --version");
printf(" %s\n", _("Print version information"));
printf(" %s\n", "-v, --variable=STRING");
printf(" %s\n\n", _("Variable to check"));
printf("%s\n", _("Valid variables are:"));
printf(" %s", "CLIENTVERSION =");
printf(" %s\n", _("Get the NSClient version"));
printf(" %s\n", _("If -l <version> is specified, will return warning if versions differ."));
printf(" %s\n", "CPULOAD =");
printf(" %s\n", _("Average CPU load on last x minutes."));
printf(" %s\n", _("Request a -l parameter with the following syntax:"));
printf(" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>."));
printf(" %s\n", _("<minute range> should be less than 24*60."));
printf(" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot."));
printf(" %s\n", "ie: -l 60,90,95,120,90,95");
printf(" %s\n", "UPTIME =");
printf(" %s\n", _("Get the uptime of the machine."));
printf(" %s\n", _("-l <unit> "));
printf(" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)"));
printf(" %s\n", _("Thresholds will use the unit specified above."));
printf(" %s\n", "USEDDISKSPACE =");
printf(" %s\n", _("Size and percentage of disk use."));
printf(" %s\n", _("Request a -l parameter containing the drive letter only."));
printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
printf(" %s\n", "MEMUSE =");
printf(" %s\n", _("Memory use."));
printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
printf(" %s\n", "SERVICESTATE =");
printf(" %s\n", _("Check the state of one or several services."));
printf(" %s\n", _("Request a -l parameters with the following syntax:"));
printf(" %s\n", _("-l <service1>,<service2>,<service3>,..."));
printf(" %s\n", _("You can specify -d SHOWALL in case you want to see working services"));
printf(" %s\n", _("in the returned string."));
printf(" %s\n", "PROCSTATE =");
printf(" %s\n", _("Check if one or several process are running."));
printf(" %s\n", _("Same syntax as SERVICESTATE."));
printf(" %s\n", "COUNTER =");
printf(" %s\n", _("Check any performance counter of Windows NT/2000."));
printf(" %s\n", _("Request a -l parameters with the following syntax:"));
printf(" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>"));
printf(" %s\n", _("The <description> parameter is optional and is given to a printf "));
printf(" %s\n", _("output command which requires a float parameter."));
printf(" %s\n", _("If <description> does not include \"%%\", it is used as a label."));
printf(" %s\n", _("Some examples:"));
printf(" %s\n", "\"Paging file usage is %%.2f %%%%\"");
printf(" %s\n", "\"%%.f %%%% paging file used.\"");
printf(" %s\n", "INSTANCES =");
printf(" %s\n", _("Check any performance counter object of Windows NT/2000."));
printf(" %s\n",
_("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>"));
printf(" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),"));
printf(" %s\n", _("if it is two words, it should be enclosed in quotes"));
printf(" %s\n", _("The returned results will be a comma-separated list of instances on "));
printf(" %s\n", _(" the selected computer for that object."));
printf(" %s\n",
_("The purpose of this is to be run from command line to determine what instances"));
printf(" %s\n",
_(" are available for monitoring without having to log onto the Windows server"));
printf(" %s\n", _(" to run Perfmon directly."));
printf(" %s\n",
_("It can also be used in scripts that automatically create the monitoring service"));
printf(" %s\n", _(" configuration files."));
printf(" %s\n", _("Some examples:"));
printf(" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process"));
printf("%s\n", _("Notes:"));
printf(" %s\n",
_("- The NSClient service should be running on the server to get any information"));
printf(" %s\n", "(http://nsclient.ready2run.nl).");
printf(" %s\n", _("- Critical thresholds should be lower than warning thresholds"));
printf(" %s\n", _("- Default port 1248 is sometimes in use by other services. The error"));
printf(" %s\n",
_("output when this happens contains \"Cannot map xxxxx to protocol number\"."));
printf(" %s\n", _("One fix for this is to change the port to something else on check_nt "));
printf(" %s\n", _("and on the client service it\'s connecting to."));
printf(UT_SUPPORT);
}
void print_usage(void) {
printf("%s\n", _("Usage:"));
printf("%s -H host -v variable [-p port] [-w warning] [-c critical]\n", progname);
printf("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
}

View file

@ -1,53 +0,0 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
enum {
PORT = 1248,
};
enum checkvars {
CHECK_NONE,
CHECK_CLIENTVERSION,
CHECK_CPULOAD,
CHECK_UPTIME,
CHECK_USEDDISKSPACE,
CHECK_SERVICESTATE,
CHECK_PROCSTATE,
CHECK_MEMUSE,
CHECK_COUNTER,
CHECK_FILEAGE,
CHECK_INSTANCES
};
typedef struct {
char *server_address;
int server_port;
char *req_password;
enum checkvars vars_to_check;
bool show_all;
char *value_list;
bool check_warning_value;
unsigned long warning_value;
bool check_critical_value;
unsigned long critical_value;
} check_nt_config;
check_nt_config check_nt_config_init() {
check_nt_config tmp = {
.server_address = NULL,
.server_port = PORT,
.req_password = NULL,
.vars_to_check = CHECK_NONE,
.show_all = false,
.value_list = NULL,
.check_warning_value = false,
.warning_value = 0,
.check_critical_value = false,
.critical_value = 0,
};
return tmp;
}

View file

@ -446,7 +446,8 @@ check_snmp_evaluation evaluate_single_unit(response_value response,
long long treated_value = (long long)response.value.uIntVal;
if (eval_params.multiplier_set || eval_params.offset_set) {
double processed = 0;
double processed = (double)response.value.uIntVal;
if (eval_params.offset_set) {
processed += eval_params.offset;
}
@ -480,15 +481,16 @@ check_snmp_evaluation evaluate_single_unit(response_value response,
} break;
case ASN_INTEGER: {
if (eval_params.multiplier_set || eval_params.offset_set) {
double processed = 0;
if (eval_params.multiplier_set) {
processed = (double)response.value.intVal * eval_params.multiplier;
}
double processed = (double)response.value.intVal;
if (eval_params.offset_set) {
processed += eval_params.offset;
}
if (eval_params.multiplier_set) {
processed *= eval_params.multiplier;
}
result_state.value.doubleVal = processed;
if (eval_params.calculate_rate && have_previous_state) {

View file

@ -1,80 +0,0 @@
#! /usr/bin/perl -w -I ..
#
# Test check_nt by having a stub check_nt daemon
#
use strict;
use Test::More;
use NPTest;
use FindBin qw($Bin);
use IO::Socket;
use IO::Select;
use POSIX;
my $port = 50000 + int(rand(1000));
my $pid = fork();
if ($pid) {
# Parent
#print "parent\n";
# give our webserver some time to startup
sleep(1);
} else {
# Child
#print "child\n";
my $server = IO::Socket::INET->new(
LocalPort => $port,
Type => SOCK_STREAM,
Reuse => 1,
Proto => "tcp",
Listen => 10,
) or die "Cannot be a tcp server on port $port: $@";
$server->autoflush(1);
print "Please contact me at port $port\n";
while (my $client = $server->accept ) {
my $data = "";
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
my ($password, $command, $arg) = split('&', $data);
if ($command eq "4") {
if ($arg eq "c") {
print $client "930000000&1000000000";
} elsif ($arg eq "d") {
print $client "UNKNOWN: Drive is not a fixed drive";
}
}
}
exit;
}
END { if ($pid) { print "Killing $pid\n"; kill "INT", $pid } };
if ($ARGV[0] && $ARGV[0] eq "-d") {
sleep 1000;
}
if (-x "./check_nt") {
plan tests => 5;
} else {
plan skip_all => "No check_nt compiled";
}
my $result;
my $command = "./check_nt -H 127.0.0.1 -p $port";
$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l c" );
is( $result->return_code, 0, "USEDDISKSPACE c");
is( $result->output, q{c:\ - total: 0.93 Gb - used: 0.07 Gb (7%) - free 0.87 Gb (93%) | 'c:\ Used Space'=0.07Gb;0.00;0.00;0.00;0.93}, "Output right" );
$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l d" );
is( $result->return_code, 3, "USEDDISKSPACE d - invalid");
is( $result->output, "Free disk space : Invalid drive", "Output right" );
$result = NPTest->testCmd( "./check_nt -v USEDDISKSPACE -l d" );
is( $result->return_code, 3, "Fail if -H missing");