diff options
author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-09-09 01:57:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-09 01:57:25 +0200 |
commit | 615fec347cd575c0ee4343aa17ee99962f375f64 (patch) | |
tree | a3603d9006ecd9ed9dadc33aa3e9eeb25dbb5113 | |
parent | 5c81b8e2ab3df0b8c56bf5ab5b30b15a816a1112 (diff) | |
parent | c43f845c22a9e879546472aa9051d7ca0803ef2a (diff) | |
download | monitoring-plugins-615fec347cd575c0ee4343aa17ee99962f375f64.tar.gz |
Merge pull request #2144 from RincewindsHat/refactor/check_snmp
Refactor check snmp:
- Switch from executing `snmpget`/`snmpgetnext` to linking directly agains net-snmp
- Refactor to use test abstraction -> allows for JSON output
-rw-r--r-- | .github/monitoring-plugins.spec | 3 | ||||
-rwxr-xr-x | .github/prepare_debian.sh | 3 | ||||
-rw-r--r-- | .github/workflows/codeql-analysis.yml | 17 | ||||
-rw-r--r-- | configure.ac | 21 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/perfdata.c | 72 | ||||
-rw-r--r-- | lib/perfdata.h | 2 | ||||
-rw-r--r-- | lib/tests/test_utils.c | 190 | ||||
-rw-r--r-- | lib/utils_base.c | 438 | ||||
-rw-r--r-- | lib/utils_base.h | 22 | ||||
-rw-r--r-- | plugins/Makefile.am | 23 | ||||
-rw-r--r-- | plugins/check_snmp.c | 1767 | ||||
-rw-r--r-- | plugins/check_snmp.d/check_snmp_helpers.c | 934 | ||||
-rw-r--r-- | plugins/check_snmp.d/check_snmp_helpers.h | 71 | ||||
-rw-r--r-- | plugins/check_snmp.d/config.h | 81 | ||||
-rw-r--r-- | plugins/t/check_snmp.t | 103 | ||||
-rwxr-xr-x | plugins/tests/check_snmp.t | 159 | ||||
-rw-r--r-- | plugins/tests/check_snmp_agent.pl | 78 | ||||
-rw-r--r-- | plugins/tests/conf/snmpd.conf | 2 | ||||
-rw-r--r-- | plugins/tests/test_check_snmp.c | 175 | ||||
-rwxr-xr-x | plugins/tests/test_check_snmp.t | 6 |
21 files changed, 2421 insertions, 1748 deletions
diff --git a/.github/monitoring-plugins.spec b/.github/monitoring-plugins.spec index 10799128..ce22606b 100644 --- a/.github/monitoring-plugins.spec +++ b/.github/monitoring-plugins.spec | |||
@@ -88,6 +88,9 @@ BuildRequires: postgresql-devel | |||
88 | # check_radius | 88 | # check_radius |
89 | BuildRequires: radcli-devel | 89 | BuildRequires: radcli-devel |
90 | 90 | ||
91 | # check_snmp | ||
92 | BuildRequires: net-snmp-devel | ||
93 | |||
91 | %description | 94 | %description |
92 | Common files for Monitoring Plugins | 95 | Common files for Monitoring Plugins |
93 | 96 | ||
diff --git a/.github/prepare_debian.sh b/.github/prepare_debian.sh index f7b6cf9f..cffe98c5 100755 --- a/.github/prepare_debian.sh +++ b/.github/prepare_debian.sh | |||
@@ -24,6 +24,7 @@ apt-get -y install perl \ | |||
24 | libpq-dev \ | 24 | libpq-dev \ |
25 | libradcli-dev \ | 25 | libradcli-dev \ |
26 | libnet-snmp-perl \ | 26 | libnet-snmp-perl \ |
27 | libsnmp-dev \ | ||
27 | procps \ | 28 | procps \ |
28 | libdbi0-dev \ | 29 | libdbi0-dev \ |
29 | libdbd-sqlite3 \ | 30 | libdbd-sqlite3 \ |
@@ -111,6 +112,8 @@ mkdir -p /var/lib/snmp/mib_indexes | |||
111 | sed -e 's/^agentaddress.*/agentaddress 127.0.0.1/' -i /etc/snmp/snmpd.conf | 112 | sed -e 's/^agentaddress.*/agentaddress 127.0.0.1/' -i /etc/snmp/snmpd.conf |
112 | service snmpd start | 113 | service snmpd start |
113 | 114 | ||
115 | sed 's/^mibs ://' -i /etc/snmp/snmp.conf | ||
116 | |||
114 | # start cron, will be used by check_nagios | 117 | # start cron, will be used by check_nagios |
115 | cron | 118 | cron |
116 | 119 | ||
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 57487eed..e01aa5fc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml | |||
@@ -57,9 +57,20 @@ jobs: | |||
57 | run: | | 57 | run: | |
58 | sudo apt update | 58 | sudo apt update |
59 | sudo apt-get install -y --no-install-recommends m4 gettext automake autoconf make build-essential | 59 | sudo apt-get install -y --no-install-recommends m4 gettext automake autoconf make build-essential |
60 | sudo apt-get install -y --no-install-recommends perl autotools-dev libdbi-dev libldap2-dev libpq-dev \ | 60 | sudo apt-get install -y --no-install-recommends perl \ |
61 | libmysqlclient-dev libradcli-dev libkrb5-dev libdbi0-dev \ | 61 | autotools-dev \ |
62 | libdbd-sqlite3 libssl-dev libcurl4-openssl-dev liburiparser-dev | 62 | libdbi-dev \ |
63 | libldap2-dev \ | ||
64 | libpq-dev \ | ||
65 | libmysqlclient-dev \ | ||
66 | libradcli-dev \ | ||
67 | libkrb5-dev \ | ||
68 | libdbi0-dev \ | ||
69 | libdbd-sqlite3 \ | ||
70 | libssl-dev \ | ||
71 | libcurl4-openssl-dev \ | ||
72 | liburiparser-dev \ | ||
73 | libsnmp-dev | ||
63 | 74 | ||
64 | - name: Configure build | 75 | - name: Configure build |
65 | run: | | 76 | run: | |
diff --git a/configure.ac b/configure.ac index ce140218..705183a2 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -1470,17 +1470,6 @@ AC_ARG_WITH(snmpgetnext_command, | |||
1470 | AS_IF([test -n "$PATH_TO_SNMPGET"], [ | 1470 | AS_IF([test -n "$PATH_TO_SNMPGET"], [ |
1471 | AC_DEFINE_UNQUOTED(PATH_TO_SNMPGET,"$PATH_TO_SNMPGET",[path to snmpget binary]) | 1471 | AC_DEFINE_UNQUOTED(PATH_TO_SNMPGET,"$PATH_TO_SNMPGET",[path to snmpget binary]) |
1472 | EXTRAS="$EXTRAS check_hpjd" | 1472 | EXTRAS="$EXTRAS check_hpjd" |
1473 | |||
1474 | dnl PATH_TO_SNMPGETNEXT is used unconditionally in check_snmp: | ||
1475 | dnl | ||
1476 | dnl https://github.com/nagios-plugins/nagios-plugins/issues/788 | ||
1477 | dnl | ||
1478 | AS_IF([test -n "$PATH_TO_SNMPGETNEXT"], [ | ||
1479 | AC_DEFINE_UNQUOTED(PATH_TO_SNMPGETNEXT,"$PATH_TO_SNMPGETNEXT",[path to snmpgetnext binary]) | ||
1480 | EXTRAS="$EXTRAS check_snmp\$(EXEEXT)" | ||
1481 | ], [ | ||
1482 | AC_MSG_WARN([Get snmpgetnext from https://net-snmp.sourceforge.io/ to build the check_snmp plugin]) | ||
1483 | ]) | ||
1484 | ], [ | 1473 | ], [ |
1485 | AC_MSG_WARN([Get snmpget from https://net-snmp.sourceforge.io/ to build the check_hpjd and check_snmp plugins]) | 1474 | AC_MSG_WARN([Get snmpget from https://net-snmp.sourceforge.io/ to build the check_hpjd and check_snmp plugins]) |
1486 | ]) | 1475 | ]) |
@@ -1493,6 +1482,16 @@ else | |||
1493 | AC_MSG_WARN([Tried $PERL - install Net::SNMP perl module if you want to use the perl snmp plugins]) | 1482 | AC_MSG_WARN([Tried $PERL - install Net::SNMP perl module if you want to use the perl snmp plugins]) |
1494 | fi | 1483 | fi |
1495 | 1484 | ||
1485 | dnl Check whether DES encryption is available (might not on RHEL) | ||
1486 | AC_COMPILE_IFELSE( | ||
1487 | [AC_LANG_PROGRAM( | ||
1488 | [[#include <net-snmp/net-snmp-config.h> | ||
1489 | #include <net-snmp/net-snmp-includes.h>]], [[oid *foo = usmDESPrivProtocol;]] | ||
1490 | )], | ||
1491 | [AC_DEFINE(HAVE_USM_DES_PRIV_PROTOCOL,1,Define whether we have DES Privacy Protocol)], | ||
1492 | [] | ||
1493 | ) | ||
1494 | |||
1496 | AC_PATH_PROG(PATH_TO_QUAKESTAT,quakestat) | 1495 | AC_PATH_PROG(PATH_TO_QUAKESTAT,quakestat) |
1497 | AC_PATH_PROG(PATH_TO_QSTAT,qstat) | 1496 | AC_PATH_PROG(PATH_TO_QSTAT,qstat) |
1498 | AC_ARG_WITH(qstat_command, | 1497 | AC_ARG_WITH(qstat_command, |
diff --git a/lib/Makefile.am b/lib/Makefile.am index a9f3ff40..27a08278 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am | |||
@@ -4,7 +4,7 @@ SUBDIRS = . tests | |||
4 | 4 | ||
5 | noinst_LIBRARIES = libmonitoringplug.a | 5 | noinst_LIBRARIES = libmonitoringplug.a |
6 | 6 | ||
7 | AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ | 7 | AM_CPPFLAGS = \ |
8 | -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins | 8 | -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins |
9 | 9 | ||
10 | libmonitoringplug_a_SOURCES = utils_base.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c | 10 | libmonitoringplug_a_SOURCES = utils_base.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c |
diff --git a/lib/perfdata.c b/lib/perfdata.c index b87de7e0..2930a8bc 100644 --- a/lib/perfdata.c +++ b/lib/perfdata.c | |||
@@ -33,7 +33,18 @@ char *pd_value_to_string(const mp_perfdata_value pd) { | |||
33 | char *pd_to_string(mp_perfdata pd) { | 33 | char *pd_to_string(mp_perfdata pd) { |
34 | assert(pd.label != NULL); | 34 | assert(pd.label != NULL); |
35 | char *result = NULL; | 35 | char *result = NULL; |
36 | asprintf(&result, "'%s'=", pd.label); | 36 | |
37 | if (strchr(pd.label, '\'') == NULL) { | ||
38 | asprintf(&result, "'%s'=", pd.label); | ||
39 | } else { | ||
40 | // we have a illegal single quote in the string | ||
41 | // replace it silently instead of complaining | ||
42 | for (char *ptr = pd.label; *ptr == '\0'; ptr++) { | ||
43 | if (*ptr == '\'') { | ||
44 | *ptr = '_'; | ||
45 | } | ||
46 | } | ||
47 | } | ||
37 | 48 | ||
38 | asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); | 49 | asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); |
39 | 50 | ||
@@ -249,7 +260,9 @@ char *mp_range_to_string(const mp_range input) { | |||
249 | return result; | 260 | return result; |
250 | } | 261 | } |
251 | 262 | ||
252 | mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); } | 263 | mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { |
264 | return mp_set_pd_value_double(pd, value); | ||
265 | } | ||
253 | 266 | ||
254 | mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { | 267 | mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { |
255 | pd.value.pd_double = value; | 268 | pd.value.pd_double = value; |
@@ -257,15 +270,25 @@ mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { | |||
257 | return pd; | 270 | return pd; |
258 | } | 271 | } |
259 | 272 | ||
260 | mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); } | 273 | mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { |
274 | return mp_set_pd_value_long_long(pd, (long long)value); | ||
275 | } | ||
261 | 276 | ||
262 | mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } | 277 | mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { |
278 | return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); | ||
279 | } | ||
263 | 280 | ||
264 | mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); } | 281 | mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { |
282 | return mp_set_pd_value_long_long(pd, (long long)value); | ||
283 | } | ||
265 | 284 | ||
266 | mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } | 285 | mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { |
286 | return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); | ||
287 | } | ||
267 | 288 | ||
268 | mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); } | 289 | mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { |
290 | return mp_set_pd_value_long_long(pd, (long long)value); | ||
291 | } | ||
269 | 292 | ||
270 | mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { | 293 | mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { |
271 | return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); | 294 | return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); |
@@ -290,19 +313,33 @@ mp_perfdata_value mp_create_pd_value_double(double value) { | |||
290 | return res; | 313 | return res; |
291 | } | 314 | } |
292 | 315 | ||
293 | mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); } | 316 | mp_perfdata_value mp_create_pd_value_float(float value) { |
317 | return mp_create_pd_value_double((double)value); | ||
318 | } | ||
294 | 319 | ||
295 | mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); } | 320 | mp_perfdata_value mp_create_pd_value_char(char value) { |
321 | return mp_create_pd_value_long_long((long long)value); | ||
322 | } | ||
296 | 323 | ||
297 | mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | 324 | mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { |
325 | return mp_create_pd_value_u_long_long((unsigned long long)value); | ||
326 | } | ||
298 | 327 | ||
299 | mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); } | 328 | mp_perfdata_value mp_create_pd_value_int(int value) { |
329 | return mp_create_pd_value_long_long((long long)value); | ||
330 | } | ||
300 | 331 | ||
301 | mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | 332 | mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { |
333 | return mp_create_pd_value_u_long_long((unsigned long long)value); | ||
334 | } | ||
302 | 335 | ||
303 | mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); } | 336 | mp_perfdata_value mp_create_pd_value_long(long value) { |
337 | return mp_create_pd_value_long_long((long long)value); | ||
338 | } | ||
304 | 339 | ||
305 | mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | 340 | mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { |
341 | return mp_create_pd_value_u_long_long((unsigned long long)value); | ||
342 | } | ||
306 | 343 | ||
307 | mp_perfdata_value mp_create_pd_value_long_long(long long value) { | 344 | mp_perfdata_value mp_create_pd_value_long_long(long long value) { |
308 | mp_perfdata_value res = {0}; | 345 | mp_perfdata_value res = {0}; |
@@ -368,6 +405,13 @@ mp_range_parsed mp_parse_range_string(const char *input) { | |||
368 | } | 405 | } |
369 | 406 | ||
370 | char *working_copy = strdup(input); | 407 | char *working_copy = strdup(input); |
408 | if (working_copy == NULL) { | ||
409 | // strdup error, probably | ||
410 | mp_range_parsed result = { | ||
411 | .error = MP_RANGE_PARSING_FAILURE, | ||
412 | }; | ||
413 | return result; | ||
414 | } | ||
371 | input = working_copy; | 415 | input = working_copy; |
372 | 416 | ||
373 | char *separator = index(working_copy, ':'); | 417 | char *separator = index(working_copy, ':'); |
diff --git a/lib/perfdata.h b/lib/perfdata.h index 7fd908a9..c5d4a61d 100644 --- a/lib/perfdata.h +++ b/lib/perfdata.h | |||
@@ -45,7 +45,7 @@ typedef struct range_struct { | |||
45 | double start; | 45 | double start; |
46 | bool start_infinity; | 46 | bool start_infinity; |
47 | double end; | 47 | double end; |
48 | int end_infinity; | 48 | bool end_infinity; |
49 | int alert_on; /* OUTSIDE (default) or INSIDE */ | 49 | int alert_on; /* OUTSIDE (default) or INSIDE */ |
50 | char *text; /* original unparsed text input */ | 50 | char *text; /* original unparsed text input */ |
51 | } range; | 51 | } range; |
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c index c3150f00..8040dec8 100644 --- a/lib/tests/test_utils.c +++ b/lib/tests/test_utils.c | |||
@@ -28,17 +28,7 @@ | |||
28 | #include "utils_base.c" | 28 | #include "utils_base.c" |
29 | 29 | ||
30 | int main(int argc, char **argv) { | 30 | int main(int argc, char **argv) { |
31 | char state_path[1024]; | 31 | plan_tests(155); |
32 | range *range; | ||
33 | double temp; | ||
34 | thresholds *thresholds = NULL; | ||
35 | int i, rc; | ||
36 | char *temp_string; | ||
37 | state_key *temp_state_key = NULL; | ||
38 | state_data *temp_state_data; | ||
39 | time_t current_time; | ||
40 | |||
41 | plan_tests(185); | ||
42 | 32 | ||
43 | ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised"); | 33 | ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised"); |
44 | 34 | ||
@@ -57,7 +47,7 @@ int main(int argc, char **argv) { | |||
57 | 47 | ||
58 | np_set_args(argc, argv); | 48 | np_set_args(argc, argv); |
59 | 49 | ||
60 | range = parse_range_string("6"); | 50 | range *range = parse_range_string("6"); |
61 | ok(range != NULL, "'6' is valid range"); | 51 | ok(range != NULL, "'6' is valid range"); |
62 | ok(range->start == 0, "Start correct"); | 52 | ok(range->start == 0, "Start correct"); |
63 | ok(range->start_infinity == false, "Not using negative infinity"); | 53 | ok(range->start_infinity == false, "Not using negative infinity"); |
@@ -97,7 +87,7 @@ int main(int argc, char **argv) { | |||
97 | free(range); | 87 | free(range); |
98 | 88 | ||
99 | range = parse_range_string("12345678901234567890:"); | 89 | range = parse_range_string("12345678901234567890:"); |
100 | temp = atof("12345678901234567890"); /* Can't just use this because number too large */ | 90 | double temp = atof("12345678901234567890"); /* Can't just use this because number too large */ |
101 | ok(range != NULL, "'12345678901234567890:' is valid range"); | 91 | ok(range != NULL, "'12345678901234567890:' is valid range"); |
102 | ok(range->start == temp, "Start correct"); | 92 | ok(range->start == temp, "Start correct"); |
103 | ok(range->start_infinity == false, "Not using negative infinity"); | 93 | ok(range->start_infinity == false, "Not using negative infinity"); |
@@ -158,32 +148,34 @@ int main(int argc, char **argv) { | |||
158 | range = parse_range_string("2:1"); | 148 | range = parse_range_string("2:1"); |
159 | ok(range == NULL, "'2:1' rejected"); | 149 | ok(range == NULL, "'2:1' rejected"); |
160 | 150 | ||
161 | rc = _set_thresholds(&thresholds, NULL, NULL); | 151 | thresholds *thresholds = NULL; |
162 | ok(rc == 0, "Thresholds (NULL, NULL) set"); | 152 | int returnCode; |
153 | returnCode = _set_thresholds(&thresholds, NULL, NULL); | ||
154 | ok(returnCode == 0, "Thresholds (NULL, NULL) set"); | ||
163 | ok(thresholds->warning == NULL, "Warning not set"); | 155 | ok(thresholds->warning == NULL, "Warning not set"); |
164 | ok(thresholds->critical == NULL, "Critical not set"); | 156 | ok(thresholds->critical == NULL, "Critical not set"); |
165 | 157 | ||
166 | rc = _set_thresholds(&thresholds, NULL, "80"); | 158 | returnCode = _set_thresholds(&thresholds, NULL, "80"); |
167 | ok(rc == 0, "Thresholds (NULL, '80') set"); | 159 | ok(returnCode == 0, "Thresholds (NULL, '80') set"); |
168 | ok(thresholds->warning == NULL, "Warning not set"); | 160 | ok(thresholds->warning == NULL, "Warning not set"); |
169 | ok(thresholds->critical->end == 80, "Critical set correctly"); | 161 | ok(thresholds->critical->end == 80, "Critical set correctly"); |
170 | 162 | ||
171 | rc = _set_thresholds(&thresholds, "5:33", NULL); | 163 | returnCode = _set_thresholds(&thresholds, "5:33", NULL); |
172 | ok(rc == 0, "Thresholds ('5:33', NULL) set"); | 164 | ok(returnCode == 0, "Thresholds ('5:33', NULL) set"); |
173 | ok(thresholds->warning->start == 5, "Warning start set"); | 165 | ok(thresholds->warning->start == 5, "Warning start set"); |
174 | ok(thresholds->warning->end == 33, "Warning end set"); | 166 | ok(thresholds->warning->end == 33, "Warning end set"); |
175 | ok(thresholds->critical == NULL, "Critical not set"); | 167 | ok(thresholds->critical == NULL, "Critical not set"); |
176 | 168 | ||
177 | rc = _set_thresholds(&thresholds, "30", "60"); | 169 | returnCode = _set_thresholds(&thresholds, "30", "60"); |
178 | ok(rc == 0, "Thresholds ('30', '60') set"); | 170 | ok(returnCode == 0, "Thresholds ('30', '60') set"); |
179 | ok(thresholds->warning->end == 30, "Warning set correctly"); | 171 | ok(thresholds->warning->end == 30, "Warning set correctly"); |
180 | ok(thresholds->critical->end == 60, "Critical set correctly"); | 172 | ok(thresholds->critical->end == 60, "Critical set correctly"); |
181 | ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); | 173 | ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); |
182 | ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); | 174 | ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); |
183 | ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); | 175 | ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); |
184 | 176 | ||
185 | rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); | 177 | returnCode = _set_thresholds(&thresholds, "-10:-2", "-30:20"); |
186 | ok(rc == 0, "Thresholds ('-30:20', '-10:-2') set"); | 178 | ok(returnCode == 0, "Thresholds ('-30:20', '-10:-2') set"); |
187 | ok(thresholds->warning->start == -10, "Warning start set correctly"); | 179 | ok(thresholds->warning->start == -10, "Warning start set correctly"); |
188 | ok(thresholds->warning->end == -2, "Warning end set correctly"); | 180 | ok(thresholds->warning->end == -2, "Warning end set correctly"); |
189 | ok(thresholds->critical->start == -30, "Critical start set correctly"); | 181 | ok(thresholds->critical->start == -30, "Critical start set correctly"); |
@@ -304,164 +296,28 @@ int main(int argc, char **argv) { | |||
304 | test = np_extract_ntpvar("", "foo"); | 296 | test = np_extract_ntpvar("", "foo"); |
305 | ok(!test, "Empty string return NULL"); | 297 | ok(!test, "Empty string return NULL"); |
306 | 298 | ||
307 | /* This is the result of running ./test_utils */ | ||
308 | temp_string = (char *)_np_state_generate_key(); | ||
309 | ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters") || | ||
310 | diag("You are probably running in wrong directory. Must run as ./test_utils"); | ||
311 | |||
312 | this_monitoring_plugin->argc = 4; | ||
313 | this_monitoring_plugin->argv[0] = "./test_utils"; | ||
314 | this_monitoring_plugin->argv[1] = "here"; | ||
315 | this_monitoring_plugin->argv[2] = "--and"; | ||
316 | this_monitoring_plugin->argv[3] = "now"; | ||
317 | temp_string = (char *)_np_state_generate_key(); | ||
318 | ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv"); | ||
319 | |||
320 | unsetenv("MP_STATE_PATH"); | ||
321 | temp_string = (char *)_np_state_calculate_location_prefix(); | ||
322 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory"); | ||
323 | |||
324 | setenv("MP_STATE_PATH", "", 1); | ||
325 | temp_string = (char *)_np_state_calculate_location_prefix(); | ||
326 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string"); | ||
327 | |||
328 | setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); | ||
329 | temp_string = (char *)_np_state_calculate_location_prefix(); | ||
330 | ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory"); | ||
331 | |||
332 | ok(temp_state_key == NULL, "temp_state_key initially empty"); | ||
333 | |||
334 | this_monitoring_plugin->argc = 1; | ||
335 | this_monitoring_plugin->argv[0] = "./test_utils"; | ||
336 | np_enable_state(NULL, 51); | ||
337 | temp_state_key = this_monitoring_plugin->state; | ||
338 | ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name"); | ||
339 | ok(!strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename"); | ||
340 | |||
341 | np_enable_state("allowedchars_in_keyname", 77); | ||
342 | temp_state_key = this_monitoring_plugin->state; | ||
343 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid()); | ||
344 | ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name"); | ||
345 | ok(!strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars"); | ||
346 | ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename"); | ||
347 | |||
348 | /* Don't do this test just yet. Will die */ | ||
349 | /* | ||
350 | np_enable_state("bad^chars$in@here", 77); | ||
351 | temp_state_key = this_monitoring_plugin->state; | ||
352 | ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" ); | ||
353 | */ | ||
354 | |||
355 | np_enable_state("funnykeyname", 54); | ||
356 | temp_state_key = this_monitoring_plugin->state; | ||
357 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid()); | ||
358 | ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name"); | ||
359 | ok(!strcmp(temp_state_key->name, "funnykeyname"), "Got key name"); | ||
360 | |||
361 | ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename"); | ||
362 | ok(temp_state_key->data_version == 54, "Version set"); | ||
363 | |||
364 | temp_state_data = np_state_read(); | ||
365 | ok(temp_state_data == NULL, "Got no state data as file does not exist"); | ||
366 | |||
367 | /* | ||
368 | temp_fp = fopen("var/statefile", "r"); | ||
369 | if (temp_fp==NULL) | ||
370 | printf("Error opening. errno=%d\n", errno); | ||
371 | printf("temp_fp=%s\n", temp_fp); | ||
372 | ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); | ||
373 | fclose(temp_fp); | ||
374 | */ | ||
375 | |||
376 | temp_state_key->_filename = "var/statefile"; | ||
377 | temp_state_data = np_state_read(); | ||
378 | ok(this_monitoring_plugin->state->state_data != NULL, "Got state data now") || | ||
379 | diag("Are you running in right directory? Will get coredump next if not"); | ||
380 | ok(this_monitoring_plugin->state->state_data->time == 1234567890, "Got time"); | ||
381 | ok(!strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected"); | ||
382 | |||
383 | temp_state_key->data_version = 53; | ||
384 | temp_state_data = np_state_read(); | ||
385 | ok(temp_state_data == NULL, "Older data version gives NULL"); | ||
386 | temp_state_key->data_version = 54; | ||
387 | |||
388 | temp_state_key->_filename = "var/nonexistent"; | ||
389 | temp_state_data = np_state_read(); | ||
390 | ok(temp_state_data == NULL, "Missing file gives NULL"); | ||
391 | ok(this_monitoring_plugin->state->state_data == NULL, "No state information"); | ||
392 | |||
393 | temp_state_key->_filename = "var/oldformat"; | ||
394 | temp_state_data = np_state_read(); | ||
395 | ok(temp_state_data == NULL, "Old file format gives NULL"); | ||
396 | |||
397 | temp_state_key->_filename = "var/baddate"; | ||
398 | temp_state_data = np_state_read(); | ||
399 | ok(temp_state_data == NULL, "Bad date gives NULL"); | ||
400 | |||
401 | temp_state_key->_filename = "var/missingdataline"; | ||
402 | temp_state_data = np_state_read(); | ||
403 | ok(temp_state_data == NULL, "Missing data line gives NULL"); | ||
404 | |||
405 | unlink("var/generated"); | ||
406 | temp_state_key->_filename = "var/generated"; | ||
407 | current_time = 1234567890; | ||
408 | np_state_write_string(current_time, "String to read"); | ||
409 | ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected"); | ||
410 | |||
411 | unlink("var/generated_directory/statefile"); | ||
412 | unlink("var/generated_directory"); | ||
413 | temp_state_key->_filename = "var/generated_directory/statefile"; | ||
414 | current_time = 1234567890; | ||
415 | np_state_write_string(current_time, "String to read"); | ||
416 | ok(system("cmp var/generated_directory/statefile var/statefile") == 0, "Have created directory"); | ||
417 | |||
418 | /* This test to check cannot write to dir - can't automate yet */ | ||
419 | /* | ||
420 | unlink("var/generated_bad_dir"); | ||
421 | mkdir("var/generated_bad_dir", S_IRUSR); | ||
422 | np_state_write_string(current_time, "String to read"); | ||
423 | */ | ||
424 | |||
425 | temp_state_key->_filename = "var/generated"; | ||
426 | time(¤t_time); | ||
427 | np_state_write_string(0, "String to read"); | ||
428 | temp_state_data = np_state_read(); | ||
429 | /* Check time is set to current_time */ | ||
430 | ok(system("cmp var/generated var/statefile > /dev/null") != 0, "Generated file should be different this time"); | ||
431 | ok(this_monitoring_plugin->state->state_data->time - current_time <= 1, "Has time generated from current time"); | ||
432 | |||
433 | /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */ | ||
434 | /* | ||
435 | temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write"; | ||
436 | np_state_write_string(0, "Bad file"); | ||
437 | */ | ||
438 | |||
439 | np_cleanup(); | ||
440 | |||
441 | ok(this_monitoring_plugin == NULL, "Free'd this_monitoring_plugin"); | ||
442 | |||
443 | ok(mp_suid() == false, "Test aren't suid"); | 299 | ok(mp_suid() == false, "Test aren't suid"); |
444 | 300 | ||
445 | /* base states with random case */ | 301 | /* base states with random case */ |
446 | char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL}; | 302 | char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL}; |
447 | 303 | ||
448 | for (i = 0; states[i] != NULL; i++) { | 304 | for (int i = 0; states[i] != NULL; i++) { |
449 | /* out of the random case states, create the lower and upper versions + numeric string one */ | 305 | /* out of the random case states, create the lower and upper versions + numeric string one |
306 | */ | ||
450 | char *statelower = strdup(states[i]); | 307 | char *statelower = strdup(states[i]); |
451 | char *stateupper = strdup(states[i]); | 308 | char *stateupper = strdup(states[i]); |
452 | char statenum[2]; | 309 | char statenum[2]; |
453 | char *temp_ptr; | 310 | for (char *temp_ptr = statelower; *temp_ptr; temp_ptr++) { |
454 | for (temp_ptr = statelower; *temp_ptr; temp_ptr++) { | 311 | *temp_ptr = (char)tolower(*temp_ptr); |
455 | *temp_ptr = tolower(*temp_ptr); | ||
456 | } | 312 | } |
457 | for (temp_ptr = stateupper; *temp_ptr; temp_ptr++) { | 313 | for (char *temp_ptr = stateupper; *temp_ptr; temp_ptr++) { |
458 | *temp_ptr = toupper(*temp_ptr); | 314 | *temp_ptr = (char)toupper(*temp_ptr); |
459 | } | 315 | } |
460 | snprintf(statenum, 2, "%i", i); | 316 | snprintf(statenum, 2, "%i", i); |
461 | 317 | ||
462 | /* Base test names, we'll append the state string */ | 318 | /* Base test names, we'll append the state string */ |
463 | char testname[64] = "Translate state string: "; | 319 | char testname[64] = "Translate state string: "; |
464 | int tlen = strlen(testname); | 320 | size_t tlen = strlen(testname); |
465 | 321 | ||
466 | strcpy(testname + tlen, states[i]); | 322 | strcpy(testname + tlen, states[i]); |
467 | ok(i == mp_translate_state(states[i]), testname); | 323 | ok(i == mp_translate_state(states[i]), testname); |
diff --git a/lib/utils_base.c b/lib/utils_base.c index c49a473f..29b393d0 100644 --- a/lib/utils_base.c +++ b/lib/utils_base.c | |||
@@ -33,12 +33,12 @@ | |||
33 | #include <unistd.h> | 33 | #include <unistd.h> |
34 | #include <sys/types.h> | 34 | #include <sys/types.h> |
35 | 35 | ||
36 | #define np_free(ptr) \ | 36 | #define np_free(ptr) \ |
37 | { \ | 37 | { \ |
38 | if (ptr) { \ | 38 | if (ptr) { \ |
39 | free(ptr); \ | 39 | free(ptr); \ |
40 | ptr = NULL; \ | 40 | ptr = NULL; \ |
41 | } \ | 41 | } \ |
42 | } | 42 | } |
43 | 43 | ||
44 | monitoring_plugin *this_monitoring_plugin = NULL; | 44 | monitoring_plugin *this_monitoring_plugin = NULL; |
@@ -46,7 +46,7 @@ monitoring_plugin *this_monitoring_plugin = NULL; | |||
46 | int timeout_state = STATE_CRITICAL; | 46 | int timeout_state = STATE_CRITICAL; |
47 | unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; | 47 | unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; |
48 | 48 | ||
49 | bool _np_state_read_file(FILE *); | 49 | bool _np_state_read_file(FILE *state_file); |
50 | 50 | ||
51 | void np_init(char *plugin_name, int argc, char **argv) { | 51 | void np_init(char *plugin_name, int argc, char **argv) { |
52 | if (this_monitoring_plugin == NULL) { | 52 | if (this_monitoring_plugin == NULL) { |
@@ -74,14 +74,6 @@ void np_set_args(int argc, char **argv) { | |||
74 | 74 | ||
75 | void np_cleanup(void) { | 75 | void np_cleanup(void) { |
76 | if (this_monitoring_plugin != NULL) { | 76 | if (this_monitoring_plugin != NULL) { |
77 | if (this_monitoring_plugin->state != NULL) { | ||
78 | if (this_monitoring_plugin->state->state_data) { | ||
79 | np_free(this_monitoring_plugin->state->state_data->data); | ||
80 | np_free(this_monitoring_plugin->state->state_data); | ||
81 | } | ||
82 | np_free(this_monitoring_plugin->state->name); | ||
83 | np_free(this_monitoring_plugin->state); | ||
84 | } | ||
85 | np_free(this_monitoring_plugin->plugin_name); | 77 | np_free(this_monitoring_plugin->plugin_name); |
86 | np_free(this_monitoring_plugin); | 78 | np_free(this_monitoring_plugin); |
87 | } | 79 | } |
@@ -153,7 +145,8 @@ range *parse_range_string(char *str) { | |||
153 | set_range_end(temp_range, end); | 145 | set_range_end(temp_range, end); |
154 | } | 146 | } |
155 | 147 | ||
156 | if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) { | 148 | if (temp_range->start_infinity || temp_range->end_infinity || |
149 | temp_range->start <= temp_range->end) { | ||
157 | return temp_range; | 150 | return temp_range; |
158 | } | 151 | } |
159 | free(temp_range); | 152 | free(temp_range); |
@@ -205,12 +198,14 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) { | |||
205 | printf("Threshold not set"); | 198 | printf("Threshold not set"); |
206 | } else { | 199 | } else { |
207 | if (my_threshold->warning) { | 200 | if (my_threshold->warning) { |
208 | printf("Warning: start=%g end=%g; ", my_threshold->warning->start, my_threshold->warning->end); | 201 | printf("Warning: start=%g end=%g; ", my_threshold->warning->start, |
202 | my_threshold->warning->end); | ||
209 | } else { | 203 | } else { |
210 | printf("Warning not set; "); | 204 | printf("Warning not set; "); |
211 | } | 205 | } |
212 | if (my_threshold->critical) { | 206 | if (my_threshold->critical) { |
213 | printf("Critical: start=%g end=%g", my_threshold->critical->start, my_threshold->critical->end); | 207 | printf("Critical: start=%g end=%g", my_threshold->critical->start, |
208 | my_threshold->critical->end); | ||
214 | } else { | 209 | } else { |
215 | printf("Critical not set"); | 210 | printf("Critical not set"); |
216 | } | 211 | } |
@@ -222,15 +217,16 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) { | |||
222 | bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) { | 217 | bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) { |
223 | bool is_inside = false; | 218 | bool is_inside = false; |
224 | 219 | ||
225 | if (my_range.end_infinity == false && my_range.start_infinity == false) { | 220 | if (!my_range.end_infinity && !my_range.start_infinity) { |
226 | // range: .........|---inside---|........... | 221 | // range: .........|---inside---|........... |
227 | // value | 222 | // value |
228 | is_inside = ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)); | 223 | is_inside = ((cmp_perfdata_value(value, my_range.start) >= 0) && |
229 | } else if (my_range.start_infinity == false && my_range.end_infinity == true) { | 224 | (cmp_perfdata_value(value, my_range.end) <= 0)); |
225 | } else if (!my_range.start_infinity && my_range.end_infinity) { | ||
230 | // range: .........|---inside--------- | 226 | // range: .........|---inside--------- |
231 | // value | 227 | // value |
232 | is_inside = (cmp_perfdata_value(my_range.start, value) < 0); | 228 | is_inside = (cmp_perfdata_value(value, my_range.start) >= 0); |
233 | } else if (my_range.start_infinity == true && my_range.end_infinity == false) { | 229 | } else if (my_range.start_infinity && !my_range.end_infinity) { |
234 | // range: -inside--------|.................... | 230 | // range: -inside--------|.................... |
235 | // value | 231 | // value |
236 | is_inside = (cmp_perfdata_value(value, my_range.end) == -1); | 232 | is_inside = (cmp_perfdata_value(value, my_range.end) == -1); |
@@ -239,7 +235,8 @@ bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) { | |||
239 | is_inside = true; | 235 | is_inside = true; |
240 | } | 236 | } |
241 | 237 | ||
242 | if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) { | 238 | if ((is_inside && my_range.alert_on_inside_range == INSIDE) || |
239 | (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) { | ||
243 | return true; | 240 | return true; |
244 | } | 241 | } |
245 | 242 | ||
@@ -256,21 +253,21 @@ bool check_range(double value, range *my_range) { | |||
256 | yes = false; | 253 | yes = false; |
257 | } | 254 | } |
258 | 255 | ||
259 | if (my_range->end_infinity == false && my_range->start_infinity == false) { | 256 | if (!my_range->end_infinity && !my_range->start_infinity) { |
260 | if ((my_range->start <= value) && (value <= my_range->end)) { | 257 | if ((my_range->start <= value) && (value <= my_range->end)) { |
261 | return no; | 258 | return no; |
262 | } | 259 | } |
263 | return yes; | 260 | return yes; |
264 | } | 261 | } |
265 | 262 | ||
266 | if (my_range->start_infinity == false && my_range->end_infinity == true) { | 263 | if (!my_range->start_infinity && my_range->end_infinity) { |
267 | if (my_range->start <= value) { | 264 | if (my_range->start <= value) { |
268 | return no; | 265 | return no; |
269 | } | 266 | } |
270 | return yes; | 267 | return yes; |
271 | } | 268 | } |
272 | 269 | ||
273 | if (my_range->start_infinity == true && my_range->end_infinity == false) { | 270 | if (my_range->start_infinity && !my_range->end_infinity) { |
274 | if (value <= my_range->end) { | 271 | if (value <= my_range->end) { |
275 | return no; | 272 | return no; |
276 | } | 273 | } |
@@ -282,12 +279,12 @@ bool check_range(double value, range *my_range) { | |||
282 | /* Returns status */ | 279 | /* Returns status */ |
283 | int get_status(double value, thresholds *my_thresholds) { | 280 | int get_status(double value, thresholds *my_thresholds) { |
284 | if (my_thresholds->critical != NULL) { | 281 | if (my_thresholds->critical != NULL) { |
285 | if (check_range(value, my_thresholds->critical) == true) { | 282 | if (check_range(value, my_thresholds->critical)) { |
286 | return STATE_CRITICAL; | 283 | return STATE_CRITICAL; |
287 | } | 284 | } |
288 | } | 285 | } |
289 | if (my_thresholds->warning != NULL) { | 286 | if (my_thresholds->warning != NULL) { |
290 | if (check_range(value, my_thresholds->warning) == true) { | 287 | if (check_range(value, my_thresholds->warning)) { |
291 | return STATE_WARNING; | 288 | return STATE_WARNING; |
292 | } | 289 | } |
293 | } | 290 | } |
@@ -296,32 +293,31 @@ int get_status(double value, thresholds *my_thresholds) { | |||
296 | 293 | ||
297 | char *np_escaped_string(const char *string) { | 294 | char *np_escaped_string(const char *string) { |
298 | char *data; | 295 | char *data; |
299 | int i; | 296 | int write_index = 0; |
300 | int j = 0; | ||
301 | data = strdup(string); | 297 | data = strdup(string); |
302 | for (i = 0; data[i]; i++) { | 298 | for (int i = 0; data[i]; i++) { |
303 | if (data[i] == '\\') { | 299 | if (data[i] == '\\') { |
304 | switch (data[++i]) { | 300 | switch (data[++i]) { |
305 | case 'n': | 301 | case 'n': |
306 | data[j++] = '\n'; | 302 | data[write_index++] = '\n'; |
307 | break; | 303 | break; |
308 | case 'r': | 304 | case 'r': |
309 | data[j++] = '\r'; | 305 | data[write_index++] = '\r'; |
310 | break; | 306 | break; |
311 | case 't': | 307 | case 't': |
312 | data[j++] = '\t'; | 308 | data[write_index++] = '\t'; |
313 | break; | 309 | break; |
314 | case '\\': | 310 | case '\\': |
315 | data[j++] = '\\'; | 311 | data[write_index++] = '\\'; |
316 | break; | 312 | break; |
317 | default: | 313 | default: |
318 | data[j++] = data[i]; | 314 | data[write_index++] = data[i]; |
319 | } | 315 | } |
320 | } else { | 316 | } else { |
321 | data[j++] = data[i]; | 317 | data[write_index++] = data[i]; |
322 | } | 318 | } |
323 | } | 319 | } |
324 | data[j] = '\0'; | 320 | data[write_index] = '\0'; |
325 | return data; | 321 | return data; |
326 | } | 322 | } |
327 | 323 | ||
@@ -336,33 +332,35 @@ int np_check_if_root(void) { return (geteuid() == 0); } | |||
336 | char *np_extract_value(const char *varlist, const char *name, char sep) { | 332 | char *np_extract_value(const char *varlist, const char *name, char sep) { |
337 | char *tmp = NULL; | 333 | char *tmp = NULL; |
338 | char *value = NULL; | 334 | char *value = NULL; |
339 | int i; | ||
340 | 335 | ||
341 | while (1) { | 336 | while (true) { |
342 | /* Strip any leading space */ | 337 | /* Strip any leading space */ |
343 | for (; isspace(varlist[0]); varlist++) | 338 | for (; isspace(varlist[0]); varlist++) { |
344 | ; | 339 | ; |
340 | } | ||
345 | 341 | ||
346 | if (strncmp(name, varlist, strlen(name)) == 0) { | 342 | if (strncmp(name, varlist, strlen(name)) == 0) { |
347 | varlist += strlen(name); | 343 | varlist += strlen(name); |
348 | /* strip trailing spaces */ | 344 | /* strip trailing spaces */ |
349 | for (; isspace(varlist[0]); varlist++) | 345 | for (; isspace(varlist[0]); varlist++) { |
350 | ; | 346 | ; |
347 | } | ||
351 | 348 | ||
352 | if (varlist[0] == '=') { | 349 | if (varlist[0] == '=') { |
353 | /* We matched the key, go past the = sign */ | 350 | /* We matched the key, go past the = sign */ |
354 | varlist++; | 351 | varlist++; |
355 | /* strip leading spaces */ | 352 | /* strip leading spaces */ |
356 | for (; isspace(varlist[0]); varlist++) | 353 | for (; isspace(varlist[0]); varlist++) { |
357 | ; | 354 | ; |
355 | } | ||
358 | 356 | ||
359 | if ((tmp = index(varlist, sep))) { | 357 | if ((tmp = index(varlist, sep))) { |
360 | /* Value is delimited by a comma */ | 358 | /* Value is delimited by a comma */ |
361 | if (tmp - varlist == 0) { | 359 | if (tmp - varlist == 0) { |
362 | continue; | 360 | continue; |
363 | } | 361 | } |
364 | value = (char *)calloc(1, tmp - varlist + 1); | 362 | value = (char *)calloc(1, (unsigned long)(tmp - varlist + 1)); |
365 | strncpy(value, varlist, tmp - varlist); | 363 | strncpy(value, varlist, (unsigned long)(tmp - varlist)); |
366 | value[tmp - varlist] = '\0'; | 364 | value[tmp - varlist] = '\0'; |
367 | } else { | 365 | } else { |
368 | /* Value is delimited by a \0 */ | 366 | /* Value is delimited by a \0 */ |
@@ -387,7 +385,7 @@ char *np_extract_value(const char *varlist, const char *name, char sep) { | |||
387 | 385 | ||
388 | /* Clean-up trailing spaces/newlines */ | 386 | /* Clean-up trailing spaces/newlines */ |
389 | if (value) { | 387 | if (value) { |
390 | for (i = strlen(value) - 1; isspace(value[i]); i--) { | 388 | for (unsigned long i = strlen(value) - 1; isspace(value[i]); i--) { |
391 | value[i] = '\0'; | 389 | value[i] = '\0'; |
392 | } | 390 | } |
393 | } | 391 | } |
@@ -429,349 +427,3 @@ int mp_translate_state(char *state_text) { | |||
429 | } | 427 | } |
430 | return ERROR; | 428 | return ERROR; |
431 | } | 429 | } |
432 | |||
433 | /* | ||
434 | * Returns a string to use as a keyname, based on an md5 hash of argv, thus | ||
435 | * hopefully a unique key per service/plugin invocation. Use the extra-opts | ||
436 | * parse of argv, so that uniqueness in parameters are reflected there. | ||
437 | */ | ||
438 | char *_np_state_generate_key(void) { | ||
439 | int i; | ||
440 | char **argv = this_monitoring_plugin->argv; | ||
441 | char keyname[41]; | ||
442 | char *p = NULL; | ||
443 | |||
444 | unsigned char result[256]; | ||
445 | |||
446 | #ifdef USE_OPENSSL | ||
447 | /* | ||
448 | * This code path is chosen if openssl is available (which should be the most common | ||
449 | * scenario). Alternatively, the gnulib implementation/ | ||
450 | * | ||
451 | */ | ||
452 | EVP_MD_CTX *ctx = EVP_MD_CTX_new(); | ||
453 | |||
454 | EVP_DigestInit(ctx, EVP_sha256()); | ||
455 | |||
456 | for (i = 0; i < this_monitoring_plugin->argc; i++) { | ||
457 | EVP_DigestUpdate(ctx, argv[i], strlen(argv[i])); | ||
458 | } | ||
459 | |||
460 | EVP_DigestFinal(ctx, result, NULL); | ||
461 | #else | ||
462 | |||
463 | struct sha256_ctx ctx; | ||
464 | |||
465 | for (i = 0; i < this_monitoring_plugin->argc; i++) { | ||
466 | sha256_process_bytes(argv[i], strlen(argv[i]), &ctx); | ||
467 | } | ||
468 | |||
469 | sha256_finish_ctx(&ctx, result); | ||
470 | #endif // FOUNDOPENSSL | ||
471 | |||
472 | for (i = 0; i < 20; ++i) { | ||
473 | sprintf(&keyname[2 * i], "%02x", result[i]); | ||
474 | } | ||
475 | |||
476 | keyname[40] = '\0'; | ||
477 | |||
478 | p = strdup(keyname); | ||
479 | if (p == NULL) { | ||
480 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | ||
481 | } | ||
482 | return p; | ||
483 | } | ||
484 | |||
485 | void _cleanup_state_data(void) { | ||
486 | if (this_monitoring_plugin->state->state_data != NULL) { | ||
487 | np_free(this_monitoring_plugin->state->state_data->data); | ||
488 | np_free(this_monitoring_plugin->state->state_data); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * Internal function. Returns either: | ||
494 | * envvar NAGIOS_PLUGIN_STATE_DIRECTORY | ||
495 | * statically compiled shared state directory | ||
496 | */ | ||
497 | char *_np_state_calculate_location_prefix(void) { | ||
498 | char *env_dir; | ||
499 | |||
500 | /* Do not allow passing MP_STATE_PATH in setuid plugins | ||
501 | * for security reasons */ | ||
502 | if (!mp_suid()) { | ||
503 | env_dir = getenv("MP_STATE_PATH"); | ||
504 | if (env_dir && env_dir[0] != '\0') { | ||
505 | return env_dir; | ||
506 | } | ||
507 | /* This is the former ENV, for backward-compatibility */ | ||
508 | env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY"); | ||
509 | if (env_dir && env_dir[0] != '\0') { | ||
510 | return env_dir; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | return NP_STATE_DIR_PREFIX; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Initiatializer for state routines. | ||
519 | * Sets variables. Generates filename. Returns np_state_key. die with | ||
520 | * UNKNOWN if exception | ||
521 | */ | ||
522 | void np_enable_state(char *keyname, int expected_data_version) { | ||
523 | state_key *this_state = NULL; | ||
524 | char *temp_filename = NULL; | ||
525 | char *temp_keyname = NULL; | ||
526 | char *p = NULL; | ||
527 | int ret; | ||
528 | |||
529 | if (this_monitoring_plugin == NULL) { | ||
530 | die(STATE_UNKNOWN, _("This requires np_init to be called")); | ||
531 | } | ||
532 | |||
533 | this_state = (state_key *)calloc(1, sizeof(state_key)); | ||
534 | if (this_state == NULL) { | ||
535 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
536 | } | ||
537 | |||
538 | if (keyname == NULL) { | ||
539 | temp_keyname = _np_state_generate_key(); | ||
540 | } else { | ||
541 | temp_keyname = strdup(keyname); | ||
542 | if (temp_keyname == NULL) { | ||
543 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | ||
544 | } | ||
545 | } | ||
546 | /* Die if invalid characters used for keyname */ | ||
547 | p = temp_keyname; | ||
548 | while (*p != '\0') { | ||
549 | if (!(isalnum(*p) || *p == '_')) { | ||
550 | die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'")); | ||
551 | } | ||
552 | p++; | ||
553 | } | ||
554 | this_state->name = temp_keyname; | ||
555 | this_state->plugin_name = this_monitoring_plugin->plugin_name; | ||
556 | this_state->data_version = expected_data_version; | ||
557 | this_state->state_data = NULL; | ||
558 | |||
559 | /* Calculate filename */ | ||
560 | ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(), | ||
561 | this_monitoring_plugin->plugin_name, this_state->name); | ||
562 | if (ret < 0) { | ||
563 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
564 | } | ||
565 | |||
566 | this_state->_filename = temp_filename; | ||
567 | |||
568 | this_monitoring_plugin->state = this_state; | ||
569 | } | ||
570 | |||
571 | /* | ||
572 | * Will return NULL if no data is available (first run). If key currently | ||
573 | * exists, read data. If state file format version is not expected, return | ||
574 | * as if no data. Get state data version number and compares to expected. | ||
575 | * If numerically lower, then return as no previous state. die with UNKNOWN | ||
576 | * if exceptional error. | ||
577 | */ | ||
578 | state_data *np_state_read(void) { | ||
579 | state_data *this_state_data = NULL; | ||
580 | FILE *statefile; | ||
581 | bool rc = false; | ||
582 | |||
583 | if (this_monitoring_plugin == NULL) { | ||
584 | die(STATE_UNKNOWN, _("This requires np_init to be called")); | ||
585 | } | ||
586 | |||
587 | /* Open file. If this fails, no previous state found */ | ||
588 | statefile = fopen(this_monitoring_plugin->state->_filename, "r"); | ||
589 | if (statefile != NULL) { | ||
590 | |||
591 | this_state_data = (state_data *)calloc(1, sizeof(state_data)); | ||
592 | if (this_state_data == NULL) { | ||
593 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
594 | } | ||
595 | |||
596 | this_state_data->data = NULL; | ||
597 | this_monitoring_plugin->state->state_data = this_state_data; | ||
598 | |||
599 | rc = _np_state_read_file(statefile); | ||
600 | |||
601 | fclose(statefile); | ||
602 | } | ||
603 | |||
604 | if (!rc) { | ||
605 | _cleanup_state_data(); | ||
606 | } | ||
607 | |||
608 | return this_monitoring_plugin->state->state_data; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * Read the state file | ||
613 | */ | ||
614 | bool _np_state_read_file(FILE *f) { | ||
615 | bool status = false; | ||
616 | size_t pos; | ||
617 | char *line; | ||
618 | int i; | ||
619 | int failure = 0; | ||
620 | time_t current_time, data_time; | ||
621 | enum { | ||
622 | STATE_FILE_VERSION, | ||
623 | STATE_DATA_VERSION, | ||
624 | STATE_DATA_TIME, | ||
625 | STATE_DATA_TEXT, | ||
626 | STATE_DATA_END | ||
627 | } expected = STATE_FILE_VERSION; | ||
628 | |||
629 | time(¤t_time); | ||
630 | |||
631 | /* Note: This introduces a limit of 1024 bytes in the string data */ | ||
632 | line = (char *)calloc(1, 1024); | ||
633 | if (line == NULL) { | ||
634 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
635 | } | ||
636 | |||
637 | while (!failure && (fgets(line, 1024, f)) != NULL) { | ||
638 | pos = strlen(line); | ||
639 | if (line[pos - 1] == '\n') { | ||
640 | line[pos - 1] = '\0'; | ||
641 | } | ||
642 | |||
643 | if (line[0] == '#') { | ||
644 | continue; | ||
645 | } | ||
646 | |||
647 | switch (expected) { | ||
648 | case STATE_FILE_VERSION: | ||
649 | i = atoi(line); | ||
650 | if (i != NP_STATE_FORMAT_VERSION) { | ||
651 | failure++; | ||
652 | } else { | ||
653 | expected = STATE_DATA_VERSION; | ||
654 | } | ||
655 | break; | ||
656 | case STATE_DATA_VERSION: | ||
657 | i = atoi(line); | ||
658 | if (i != this_monitoring_plugin->state->data_version) { | ||
659 | failure++; | ||
660 | } else { | ||
661 | expected = STATE_DATA_TIME; | ||
662 | } | ||
663 | break; | ||
664 | case STATE_DATA_TIME: | ||
665 | /* If time > now, error */ | ||
666 | data_time = strtoul(line, NULL, 10); | ||
667 | if (data_time > current_time) { | ||
668 | failure++; | ||
669 | } else { | ||
670 | this_monitoring_plugin->state->state_data->time = data_time; | ||
671 | expected = STATE_DATA_TEXT; | ||
672 | } | ||
673 | break; | ||
674 | case STATE_DATA_TEXT: | ||
675 | this_monitoring_plugin->state->state_data->data = strdup(line); | ||
676 | if (this_monitoring_plugin->state->state_data->data == NULL) { | ||
677 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | ||
678 | } | ||
679 | expected = STATE_DATA_END; | ||
680 | status = true; | ||
681 | break; | ||
682 | case STATE_DATA_END:; | ||
683 | } | ||
684 | } | ||
685 | |||
686 | np_free(line); | ||
687 | return status; | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * If time=NULL, use current time. Create state file, with state format | ||
692 | * version, default text. Writes version, time, and data. Avoid locking | ||
693 | * problems - use mv to write and then swap. Possible loss of state data if | ||
694 | * two things writing to same key at same time. | ||
695 | * Will die with UNKNOWN if errors | ||
696 | */ | ||
697 | void np_state_write_string(time_t data_time, char *data_string) { | ||
698 | FILE *fp; | ||
699 | char *temp_file = NULL; | ||
700 | int fd = 0, result = 0; | ||
701 | time_t current_time; | ||
702 | char *directories = NULL; | ||
703 | char *p = NULL; | ||
704 | |||
705 | if (data_time == 0) { | ||
706 | time(¤t_time); | ||
707 | } else { | ||
708 | current_time = data_time; | ||
709 | } | ||
710 | |||
711 | /* If file doesn't currently exist, create directories */ | ||
712 | if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) { | ||
713 | result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename); | ||
714 | if (result < 0) { | ||
715 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
716 | } | ||
717 | |||
718 | for (p = directories + 1; *p; p++) { | ||
719 | if (*p == '/') { | ||
720 | *p = '\0'; | ||
721 | if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) { | ||
722 | /* Can't free this! Otherwise error message is wrong! */ | ||
723 | /* np_free(directories); */ | ||
724 | die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); | ||
725 | } | ||
726 | *p = '/'; | ||
727 | } | ||
728 | } | ||
729 | np_free(directories); | ||
730 | } | ||
731 | |||
732 | result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename); | ||
733 | if (result < 0) { | ||
734 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
735 | } | ||
736 | |||
737 | if ((fd = mkstemp(temp_file)) == -1) { | ||
738 | np_free(temp_file); | ||
739 | die(STATE_UNKNOWN, _("Cannot create temporary filename")); | ||
740 | } | ||
741 | |||
742 | fp = (FILE *)fdopen(fd, "w"); | ||
743 | if (fp == NULL) { | ||
744 | close(fd); | ||
745 | unlink(temp_file); | ||
746 | np_free(temp_file); | ||
747 | die(STATE_UNKNOWN, _("Unable to open temporary state file")); | ||
748 | } | ||
749 | |||
750 | fprintf(fp, "# NP State file\n"); | ||
751 | fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION); | ||
752 | fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version); | ||
753 | fprintf(fp, "%lu\n", current_time); | ||
754 | fprintf(fp, "%s\n", data_string); | ||
755 | |||
756 | fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP); | ||
757 | |||
758 | fflush(fp); | ||
759 | |||
760 | result = fclose(fp); | ||
761 | |||
762 | fsync(fd); | ||
763 | |||
764 | if (result != 0) { | ||
765 | unlink(temp_file); | ||
766 | np_free(temp_file); | ||
767 | die(STATE_UNKNOWN, _("Error writing temp file")); | ||
768 | } | ||
769 | |||
770 | if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) { | ||
771 | unlink(temp_file); | ||
772 | np_free(temp_file); | ||
773 | die(STATE_UNKNOWN, _("Cannot rename state temp file")); | ||
774 | } | ||
775 | |||
776 | np_free(temp_file); | ||
777 | } | ||
diff --git a/lib/utils_base.h b/lib/utils_base.h index 123066f8..f1c99a54 100644 --- a/lib/utils_base.h +++ b/lib/utils_base.h | |||
@@ -8,7 +8,6 @@ | |||
8 | #include "./perfdata.h" | 8 | #include "./perfdata.h" |
9 | #include "./thresholds.h" | 9 | #include "./thresholds.h" |
10 | 10 | ||
11 | |||
12 | #ifndef USE_OPENSSL | 11 | #ifndef USE_OPENSSL |
13 | # include "sha256.h" | 12 | # include "sha256.h" |
14 | #endif | 13 | #endif |
@@ -26,25 +25,8 @@ | |||
26 | #define OUTSIDE 0 | 25 | #define OUTSIDE 0 |
27 | #define INSIDE 1 | 26 | #define INSIDE 1 |
28 | 27 | ||
29 | #define NP_STATE_FORMAT_VERSION 1 | ||
30 | |||
31 | typedef struct state_data_struct { | ||
32 | time_t time; | ||
33 | void *data; | ||
34 | int length; /* Of binary data */ | ||
35 | } state_data; | ||
36 | |||
37 | typedef struct state_key_struct { | ||
38 | char *name; | ||
39 | char *plugin_name; | ||
40 | int data_version; | ||
41 | char *_filename; | ||
42 | state_data *state_data; | ||
43 | } state_key; | ||
44 | |||
45 | typedef struct np_struct { | 28 | typedef struct np_struct { |
46 | char *plugin_name; | 29 | char *plugin_name; |
47 | state_key *state; | ||
48 | int argc; | 30 | int argc; |
49 | char **argv; | 31 | char **argv; |
50 | } monitoring_plugin; | 32 | } monitoring_plugin; |
@@ -100,10 +82,6 @@ char *np_extract_value(const char *, const char *, char); | |||
100 | */ | 82 | */ |
101 | int mp_translate_state(char *); | 83 | int mp_translate_state(char *); |
102 | 84 | ||
103 | void np_enable_state(char *, int); | ||
104 | state_data *np_state_read(void); | ||
105 | void np_state_write_string(time_t, char *); | ||
106 | |||
107 | void np_init(char *, int argc, char **argv); | 85 | void np_init(char *, int argc, char **argv); |
108 | void np_set_args(int argc, char **argv); | 86 | void np_set_args(int argc, char **argv); |
109 | void np_cleanup(void); | 87 | void np_cleanup(void); |
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 5994b405..deae938d 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am | |||
@@ -13,8 +13,14 @@ AM_CFLAGS = -DNP_VERSION='"$(NP_VERSION)"' | |||
13 | 13 | ||
14 | VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t | 14 | VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t |
15 | 15 | ||
16 | AM_CPPFLAGS = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl \ | 16 | AM_CPPFLAGS = -I.. \ |
17 | @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@ | 17 | -I$(top_srcdir)/lib \ |
18 | -I$(top_srcdir)/gl \ | ||
19 | -I$(top_srcdir)/intl \ | ||
20 | -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ | ||
21 | @LDAPINCLUDE@ \ | ||
22 | @PGINCLUDE@ \ | ||
23 | @SSLINCLUDE@ | ||
18 | 24 | ||
19 | localedir = $(datadir)/locale | 25 | localedir = $(datadir)/locale |
20 | # gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this | 26 | # gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this |
@@ -30,22 +36,25 @@ libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http che | |||
30 | check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \ | 36 | check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \ |
31 | check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ | 37 | check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ |
32 | check_ups check_users negate \ | 38 | check_ups check_users negate \ |
33 | urlize @EXTRAS@ | 39 | urlize @EXTRAS@ \ |
40 | check_snmp | ||
34 | 41 | ||
35 | check_tcp_programs = check_ftp check_imap check_nntp check_pop \ | 42 | check_tcp_programs = check_ftp check_imap check_nntp check_pop \ |
36 | check_udp check_clamd @check_tcp_ssl@ | 43 | check_udp check_clamd @check_tcp_ssl@ |
37 | 44 | ||
38 | EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ | 45 | EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \ |
39 | check_swap check_fping check_ldap check_game check_dig \ | 46 | check_swap check_fping check_ldap check_game check_dig \ |
40 | check_nagios check_by_ssh check_dns check_nt check_ide_smart \ | 47 | check_nagios check_by_ssh check_dns check_nt check_ide_smart \ |
41 | check_procs check_mysql_query check_apt check_dbi check_curl \ | 48 | check_procs check_mysql_query check_apt check_dbi check_curl \ |
42 | \ | 49 | \ |
43 | tests/test_check_swap \ | 50 | tests/test_check_swap \ |
51 | tests/test_check_snmp \ | ||
44 | tests/test_check_disk | 52 | tests/test_check_disk |
45 | 53 | ||
46 | SUBDIRS = picohttpparser | 54 | SUBDIRS = picohttpparser |
47 | 55 | ||
48 | np_test_scripts = tests/test_check_swap.t \ | 56 | np_test_scripts = tests/test_check_swap.t \ |
57 | tests/test_check_snmp.t \ | ||
49 | tests/test_check_disk.t | 58 | tests/test_check_disk.t |
50 | 59 | ||
51 | EXTRA_DIST = t \ | 60 | EXTRA_DIST = t \ |
@@ -78,6 +87,7 @@ EXTRA_DIST = t \ | |||
78 | check_ping.d \ | 87 | check_ping.d \ |
79 | check_by_ssh.d \ | 88 | check_by_ssh.d \ |
80 | check_smtp.d \ | 89 | check_smtp.d \ |
90 | check_snmp.d \ | ||
81 | check_mysql.d \ | 91 | check_mysql.d \ |
82 | check_ntp_time.d \ | 92 | check_ntp_time.d \ |
83 | check_dig.d \ | 93 | check_dig.d \ |
@@ -151,7 +161,10 @@ check_ping_LDADD = $(NETLIBS) | |||
151 | check_procs_LDADD = $(BASEOBJS) | 161 | check_procs_LDADD = $(BASEOBJS) |
152 | check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS) | 162 | check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS) |
153 | check_real_LDADD = $(NETLIBS) | 163 | check_real_LDADD = $(NETLIBS) |
164 | check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c | ||
154 | check_snmp_LDADD = $(BASEOBJS) | 165 | check_snmp_LDADD = $(BASEOBJS) |
166 | check_snmp_LDFLAGS = $(AM_LDFLAGS) `net-snmp-config --libs` | ||
167 | check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags` | ||
155 | check_smtp_LDADD = $(SSLOBJS) | 168 | check_smtp_LDADD = $(SSLOBJS) |
156 | check_ssh_LDADD = $(NETLIBS) | 169 | check_ssh_LDADD = $(NETLIBS) |
157 | check_swap_SOURCES = check_swap.c check_swap.d/swap.c | 170 | check_swap_SOURCES = check_swap.c check_swap.d/swap.c |
@@ -173,6 +186,8 @@ endif | |||
173 | 186 | ||
174 | tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap | 187 | tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap |
175 | tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c | 188 | tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c |
189 | tests_test_check_snmp_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap | ||
190 | tests_test_check_snmp_SOURCES = tests/test_check_snmp.c check_snmp.d/check_snmp_helpers.c | ||
176 | tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap | 191 | tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap |
177 | tests_test_check_disk_SOURCES = tests/test_check_disk.c | 192 | tests_test_check_disk_SOURCES = tests/test_check_disk.c |
178 | 193 | ||
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c index c1d8e2dd..a5a7afe8 100644 --- a/plugins/check_snmp.c +++ b/plugins/check_snmp.c | |||
@@ -32,716 +32,494 @@ const char *progname = "check_snmp"; | |||
32 | const char *copyright = "1999-2024"; | 32 | const char *copyright = "1999-2024"; |
33 | const char *email = "devel@monitoring-plugins.org"; | 33 | const char *email = "devel@monitoring-plugins.org"; |
34 | 34 | ||
35 | #include "common.h" | 35 | #include "./common.h" |
36 | #include "runcmd.h" | 36 | #include "./runcmd.h" |
37 | #include "utils.h" | 37 | #include "./utils.h" |
38 | #include "utils_cmd.h" | 38 | #include "../lib/states.h" |
39 | 39 | ||
40 | #define DEFAULT_COMMUNITY "public" | 40 | #include "../lib/utils_base.h" |
41 | #define DEFAULT_PORT "161" | 41 | #include "../lib/output.h" |
42 | #define DEFAULT_MIBLIST "ALL" | 42 | #include "check_snmp.d/check_snmp_helpers.h" |
43 | #define DEFAULT_PROTOCOL "1" | 43 | |
44 | #define DEFAULT_RETRIES 5 | 44 | #include <bits/getopt_core.h> |
45 | #define DEFAULT_AUTH_PROTOCOL "MD5" | 45 | #include <bits/getopt_ext.h> |
46 | #define DEFAULT_PRIV_PROTOCOL "DES" | 46 | #include <strings.h> |
47 | #define DEFAULT_DELIMITER "=" | 47 | #include <stdint.h> |
48 | #define DEFAULT_OUTPUT_DELIMITER " " | 48 | |
49 | #define DEFAULT_BUFFER_SIZE 100 | 49 | #include "check_snmp.d/config.h" |
50 | 50 | #include <stdlib.h> | |
51 | #define mark(a) ((a) != 0 ? "*" : "") | 51 | #include <arpa/inet.h> |
52 | 52 | #include <net-snmp/library/parse.h> | |
53 | #define CHECK_UNDEF 0 | 53 | #include <net-snmp/net-snmp-config.h> |
54 | #define CRIT_PRESENT 1 | 54 | #include <net-snmp/net-snmp-includes.h> |
55 | #define CRIT_STRING 2 | 55 | #include <net-snmp/library/snmp.h> |
56 | #define CRIT_REGEX 4 | 56 | #include <net-snmp/library/keytools.h> |
57 | #define WARN_PRESENT 8 | 57 | #include <net-snmp/library/snmp_api.h> |
58 | 58 | #include <net-snmp/session_api.h> | |
59 | #define OID_COUNT_STEP 8 | 59 | #include <net-snmp/definitions.h> |
60 | 60 | #include <net-snmp/library/asn1.h> | |
61 | /* Longopts only arguments */ | 61 | #include <net-snmp/mib_api.h> |
62 | #define L_CALCULATE_RATE CHAR_MAX + 1 | 62 | #include <net-snmp/library/snmp_impl.h> |
63 | #define L_RATE_MULTIPLIER CHAR_MAX + 2 | 63 | #include <string.h> |
64 | #define L_INVERT_SEARCH CHAR_MAX + 3 | 64 | #include "../gl/regex.h" |
65 | #define L_OFFSET CHAR_MAX + 4 | 65 | #include "../gl/base64.h" |
66 | #define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX + 5 | 66 | #include <assert.h> |
67 | 67 | ||
68 | /* Gobble to string - stop incrementing c when c[0] match one of the | 68 | const char DEFAULT_COMMUNITY[] = "public"; |
69 | * characters in s */ | 69 | const char DEFAULT_MIBLIST[] = "ALL"; |
70 | #define GOBBLE_TOS(c, s) \ | 70 | #define DEFAULT_AUTH_PROTOCOL "MD5" |
71 | while (c[0] != '\0' && strchr(s, c[0]) == NULL) { \ | 71 | |
72 | c++; \ | 72 | #ifdef HAVE_USM_DES_PRIV_PROTOCOL |
73 | # define DEFAULT_PRIV_PROTOCOL "DES" | ||
74 | #else | ||
75 | # define DEFAULT_PRIV_PROTOCOL "AES" | ||
76 | #endif | ||
77 | |||
78 | typedef struct proces_arguments_wrapper { | ||
79 | int errorcode; | ||
80 | check_snmp_config config; | ||
81 | } process_arguments_wrapper; | ||
82 | |||
83 | static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | ||
84 | static char *trim_whitespaces_and_check_quoting(char *str); | ||
85 | static char *get_next_argument(char *str); | ||
86 | void print_usage(void); | ||
87 | void print_help(void); | ||
88 | |||
89 | int verbose = 0; | ||
90 | |||
91 | typedef struct { | ||
92 | int errorcode; | ||
93 | char *state_string; | ||
94 | } gen_state_string_type; | ||
95 | gen_state_string_type gen_state_string(check_snmp_state_entry *entries, size_t num_of_entries) { | ||
96 | char *encoded_string = NULL; | ||
97 | gen_state_string_type result = {.errorcode = OK, .state_string = NULL}; | ||
98 | |||
99 | if (verbose > 1) { | ||
100 | printf("%s:\n", __FUNCTION__); | ||
101 | for (size_t i = 0; i < num_of_entries; i++) { | ||
102 | printf("Entry timestamp %lu: %s", entries[i].timestamp, ctime(&entries[i].timestamp)); | ||
103 | switch (entries[i].type) { | ||
104 | case ASN_GAUGE: | ||
105 | printf("Type GAUGE\n"); | ||
106 | break; | ||
107 | case ASN_TIMETICKS: | ||
108 | printf("Type TIMETICKS\n"); | ||
109 | break; | ||
110 | case ASN_COUNTER: | ||
111 | printf("Type COUNTER\n"); | ||
112 | break; | ||
113 | case ASN_UINTEGER: | ||
114 | printf("Type UINTEGER\n"); | ||
115 | break; | ||
116 | case ASN_COUNTER64: | ||
117 | printf("Type COUNTER64\n"); | ||
118 | break; | ||
119 | case ASN_FLOAT: | ||
120 | printf("Type FLOAT\n"); | ||
121 | case ASN_DOUBLE: | ||
122 | printf("Type DOUBLE\n"); | ||
123 | break; | ||
124 | case ASN_INTEGER: | ||
125 | printf("Type INTEGER\n"); | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | switch (entries[i].type) { | ||
130 | case ASN_GAUGE: | ||
131 | case ASN_TIMETICKS: | ||
132 | case ASN_COUNTER: | ||
133 | case ASN_UINTEGER: | ||
134 | case ASN_COUNTER64: | ||
135 | printf("Value %llu\n", entries[i].value.uIntVal); | ||
136 | break; | ||
137 | case ASN_FLOAT: | ||
138 | case ASN_DOUBLE: | ||
139 | printf("Value %f\n", entries[i].value.doubleVal); | ||
140 | break; | ||
141 | case ASN_INTEGER: | ||
142 | printf("Value %lld\n", entries[i].value.intVal); | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | idx_t encoded = base64_encode_alloc((const char *)entries, | ||
149 | (idx_t)(num_of_entries * sizeof(check_snmp_state_entry)), | ||
150 | &encoded_string); | ||
151 | |||
152 | if (encoded > 0 && encoded_string != NULL) { | ||
153 | // success | ||
154 | if (verbose > 1) { | ||
155 | printf("encoded string: %s\n", encoded_string); | ||
156 | printf("encoded string length: %lu\n", strlen(encoded_string)); | ||
157 | } | ||
158 | result.state_string = encoded_string; | ||
159 | return result; | ||
73 | } | 160 | } |
74 | /* Given c, keep track of backslashes (bk) and double-quotes (dq) | 161 | result.errorcode = ERROR; |
75 | * from c[0] */ | 162 | return result; |
76 | #define COUNT_SEQ(c, bk, dq) \ | 163 | } |
77 | switch (c[0]) { \ | 164 | |
78 | case '\\': \ | 165 | typedef struct { |
79 | if (bk) \ | 166 | int errorcode; |
80 | bk--; \ | 167 | check_snmp_state_entry *state; |
81 | else \ | 168 | } recover_state_data_type; |
82 | bk++; \ | 169 | recover_state_data_type recover_state_data(char *state_string, idx_t state_string_length) { |
83 | break; \ | 170 | recover_state_data_type result = {.errorcode = OK, .state = NULL}; |
84 | case '"': \ | 171 | |
85 | if (!dq) { \ | 172 | if (verbose > 1) { |
86 | dq++; \ | 173 | printf("%s:\n", __FUNCTION__); |
87 | } else if (!bk) { \ | 174 | printf("State string: %s\n", state_string); |
88 | dq--; \ | 175 | printf("State string length: %lu\n", state_string_length); |
89 | } else { \ | ||
90 | bk--; \ | ||
91 | } \ | ||
92 | break; \ | ||
93 | } | 176 | } |
94 | 177 | ||
95 | static int process_arguments(int, char **); | 178 | idx_t outlen = 0; |
96 | static int validate_arguments(void); | 179 | bool decoded = |
97 | static char *thisarg(char *str); | 180 | base64_decode_alloc(state_string, state_string_length, (char **)&result.state, &outlen); |
98 | static char *nextarg(char *str); | 181 | |
99 | void print_usage(void); | 182 | if (!decoded) { |
100 | static void print_help(void); | 183 | if (verbose) { |
101 | static char *multiply(char *str); | 184 | printf("Failed to decode state string\n"); |
102 | 185 | } | |
103 | #include "regex.h" | 186 | // failure to decode |
104 | static char regex_expect[MAX_INPUT_BUFFER] = ""; | 187 | result.errorcode = ERROR; |
105 | static regex_t preg; | 188 | return result; |
106 | static regmatch_t pmatch[10]; | 189 | } |
107 | static char errbuf[MAX_INPUT_BUFFER] = ""; | 190 | |
108 | static char perfstr[MAX_INPUT_BUFFER] = "| "; | 191 | if (result.state == NULL) { |
109 | static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; | 192 | // Memory Error? |
110 | static int eflags = 0; | 193 | result.errorcode = ERROR; |
111 | static int errcode, excode; | 194 | return result; |
112 | 195 | } | |
113 | static char *server_address = NULL; | 196 | |
114 | static char *community = NULL; | 197 | if (verbose > 1) { |
115 | static char **contextargs = NULL; | 198 | printf("Recovered %lu entries of size %lu\n", |
116 | static char *context = NULL; | 199 | (size_t)outlen / sizeof(check_snmp_state_entry), outlen); |
117 | static char **authpriv = NULL; | 200 | |
118 | static char *proto = NULL; | 201 | for (size_t i = 0; i < (size_t)outlen / sizeof(check_snmp_state_entry); i++) { |
119 | static char *seclevel = NULL; | 202 | printf("Entry timestamp %lu: %s", result.state[i].timestamp, |
120 | static char *secname = NULL; | 203 | ctime(&result.state[i].timestamp)); |
121 | static char *authproto = NULL; | 204 | switch (result.state[i].type) { |
122 | static char *privproto = NULL; | 205 | case ASN_GAUGE: |
123 | static char *authpasswd = NULL; | 206 | printf("Type GAUGE\n"); |
124 | static char *privpasswd = NULL; | 207 | break; |
125 | static int nulloid = STATE_UNKNOWN; | 208 | case ASN_TIMETICKS: |
126 | static char **oids = NULL; | 209 | printf("Type TIMETICKS\n"); |
127 | static size_t oids_size = 0; | 210 | break; |
128 | static char *label; | 211 | case ASN_COUNTER: |
129 | static char *units; | 212 | printf("Type COUNTER\n"); |
130 | static char *port; | 213 | break; |
131 | static char *snmpcmd; | 214 | case ASN_UINTEGER: |
132 | static char string_value[MAX_INPUT_BUFFER] = ""; | 215 | printf("Type UINTEGER\n"); |
133 | static int invert_search = 0; | 216 | break; |
134 | static char **labels = NULL; | 217 | case ASN_COUNTER64: |
135 | static char **unitv = NULL; | 218 | printf("Type COUNTER64\n"); |
136 | static size_t nlabels = 0; | 219 | break; |
137 | static size_t labels_size = OID_COUNT_STEP; | 220 | case ASN_FLOAT: |
138 | static size_t nunits = 0; | 221 | printf("Type FLOAT\n"); |
139 | static size_t unitv_size = OID_COUNT_STEP; | 222 | case ASN_DOUBLE: |
140 | static size_t numoids = 0; | 223 | printf("Type DOUBLE\n"); |
141 | static int numauthpriv = 0; | 224 | break; |
142 | static int numcontext = 0; | 225 | case ASN_INTEGER: |
143 | static int verbose = 0; | 226 | printf("Type INTEGER\n"); |
144 | static bool usesnmpgetnext = false; | 227 | break; |
145 | static char *warning_thresholds = NULL; | 228 | } |
146 | static char *critical_thresholds = NULL; | 229 | |
147 | static thresholds **thlds; | 230 | switch (result.state[i].type) { |
148 | static size_t thlds_size = OID_COUNT_STEP; | 231 | case ASN_GAUGE: |
149 | static double *response_value; | 232 | case ASN_TIMETICKS: |
150 | static size_t response_size = OID_COUNT_STEP; | 233 | case ASN_COUNTER: |
151 | static int retries = 0; | 234 | case ASN_UINTEGER: |
152 | static int *eval_method; | 235 | case ASN_COUNTER64: |
153 | static size_t eval_size = OID_COUNT_STEP; | 236 | printf("Value %llu\n", result.state[i].value.uIntVal); |
154 | static char *delimiter; | 237 | break; |
155 | static char *output_delim; | 238 | case ASN_FLOAT: |
156 | static char *miblist = NULL; | 239 | case ASN_DOUBLE: |
157 | static bool needmibs = false; | 240 | printf("Value %f\n", result.state[i].value.doubleVal); |
158 | static int calculate_rate = 0; | 241 | break; |
159 | static double offset = 0.0; | 242 | case ASN_INTEGER: |
160 | static int rate_multiplier = 1; | 243 | printf("Value %lld\n", result.state[i].value.intVal); |
161 | static state_data *previous_state; | 244 | break; |
162 | static double *previous_value; | 245 | } |
163 | static size_t previous_size = OID_COUNT_STEP; | 246 | } |
164 | static int perf_labels = 1; | 247 | } |
165 | static char *ip_version = ""; | 248 | |
166 | static double multiplier = 1.0; | 249 | return result; |
167 | static char *fmtstr = ""; | ||
168 | static bool fmtstr_set = false; | ||
169 | static char buffer[DEFAULT_BUFFER_SIZE]; | ||
170 | static bool ignore_mib_parsing_errors = false; | ||
171 | |||
172 | static char *fix_snmp_range(char *th) { | ||
173 | double left; | ||
174 | double right; | ||
175 | char *colon; | ||
176 | char *ret; | ||
177 | |||
178 | if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0') | ||
179 | return th; | ||
180 | |||
181 | left = strtod(th, NULL); | ||
182 | right = strtod(colon + 1, NULL); | ||
183 | if (right >= left) | ||
184 | return th; | ||
185 | |||
186 | if ((ret = malloc(strlen(th) + 2)) == NULL) | ||
187 | die(STATE_UNKNOWN, _("Cannot malloc")); | ||
188 | *colon = '\0'; | ||
189 | sprintf(ret, "@%s:%s", colon + 1, th); | ||
190 | free(th); | ||
191 | return ret; | ||
192 | } | 250 | } |
193 | 251 | ||
194 | int main(int argc, char **argv) { | 252 | int main(int argc, char **argv) { |
195 | int len; | ||
196 | int total_oids; | ||
197 | size_t line; | ||
198 | unsigned int bk_count = 0; | ||
199 | unsigned int dq_count = 0; | ||
200 | int iresult = STATE_UNKNOWN; | ||
201 | int result = STATE_UNKNOWN; | ||
202 | int return_code = 0; | ||
203 | int external_error = 0; | ||
204 | char **command_line = NULL; | ||
205 | char *cl_hidden_auth = NULL; | ||
206 | char *oidname = NULL; | ||
207 | char *response = NULL; | ||
208 | char *mult_resp = NULL; | ||
209 | char *outbuff; | ||
210 | char *ptr = NULL; | ||
211 | char *show = NULL; | ||
212 | char *th_warn = NULL; | ||
213 | char *th_crit = NULL; | ||
214 | char type[8] = ""; | ||
215 | output chld_out; | ||
216 | output chld_err; | ||
217 | char *previous_string = NULL; | ||
218 | char *ap = NULL; | ||
219 | char *state_string = NULL; | ||
220 | size_t response_length; | ||
221 | size_t current_length; | ||
222 | size_t string_length; | ||
223 | char *temp_string = NULL; | ||
224 | char *quote_string = NULL; | ||
225 | time_t current_time; | ||
226 | double temp_double; | ||
227 | time_t duration; | ||
228 | char *conv = "12345678"; | ||
229 | int is_counter = 0; | ||
230 | |||
231 | setlocale(LC_ALL, ""); | 253 | setlocale(LC_ALL, ""); |
232 | bindtextdomain(PACKAGE, LOCALEDIR); | 254 | bindtextdomain(PACKAGE, LOCALEDIR); |
233 | textdomain(PACKAGE); | 255 | textdomain(PACKAGE); |
234 | 256 | ||
235 | labels = malloc(labels_size * sizeof(*labels)); | ||
236 | unitv = malloc(unitv_size * sizeof(*unitv)); | ||
237 | thlds = malloc(thlds_size * sizeof(*thlds)); | ||
238 | response_value = malloc(response_size * sizeof(*response_value)); | ||
239 | previous_value = malloc(previous_size * sizeof(*previous_value)); | ||
240 | eval_method = calloc(eval_size, sizeof(*eval_method)); | ||
241 | oids = calloc(oids_size, sizeof(char *)); | ||
242 | |||
243 | label = strdup("SNMP"); | ||
244 | units = strdup(""); | ||
245 | port = strdup(DEFAULT_PORT); | ||
246 | outbuff = strdup(""); | ||
247 | delimiter = strdup(" = "); | ||
248 | output_delim = strdup(DEFAULT_OUTPUT_DELIMITER); | ||
249 | timeout_interval = DEFAULT_SOCKET_TIMEOUT; | 257 | timeout_interval = DEFAULT_SOCKET_TIMEOUT; |
250 | retries = DEFAULT_RETRIES; | ||
251 | 258 | ||
252 | np_init((char *)progname, argc, argv); | 259 | np_init((char *)progname, argc, argv); |
253 | 260 | ||
261 | state_key stateKey = np_enable_state(NULL, 1, progname, argc, argv); | ||
262 | |||
254 | /* Parse extra opts if any */ | 263 | /* Parse extra opts if any */ |
255 | argv = np_extra_opts(&argc, argv, progname); | 264 | argv = np_extra_opts(&argc, argv, progname); |
256 | 265 | ||
257 | np_set_args(argc, argv); | 266 | np_set_args(argc, argv); |
258 | 267 | ||
259 | time(¤t_time); | 268 | // Initialize net-snmp before touching the session we are going to use |
269 | init_snmp("check_snmp"); | ||
260 | 270 | ||
261 | if (process_arguments(argc, argv) == ERROR) | 271 | process_arguments_wrapper paw_tmp = process_arguments(argc, argv); |
272 | if (paw_tmp.errorcode == ERROR) { | ||
262 | usage4(_("Could not parse arguments")); | 273 | usage4(_("Could not parse arguments")); |
263 | |||
264 | if (calculate_rate) { | ||
265 | if (!strcmp(label, "SNMP")) | ||
266 | label = strdup("SNMP RATE"); | ||
267 | |||
268 | size_t i = 0; | ||
269 | |||
270 | previous_state = np_state_read(); | ||
271 | if (previous_state != NULL) { | ||
272 | /* Split colon separated values */ | ||
273 | previous_string = strdup((char *)previous_state->data); | ||
274 | while ((ap = strsep(&previous_string, ":")) != NULL) { | ||
275 | if (verbose > 2) | ||
276 | printf("State for %zd=%s\n", i, ap); | ||
277 | while (i >= previous_size) { | ||
278 | previous_size += OID_COUNT_STEP; | ||
279 | previous_value = realloc(previous_value, previous_size * sizeof(*previous_value)); | ||
280 | } | ||
281 | previous_value[i++] = strtod(ap, NULL); | ||
282 | } | ||
283 | } | ||
284 | } | 274 | } |
285 | 275 | ||
286 | /* Populate the thresholds */ | 276 | check_snmp_config config = paw_tmp.config; |
287 | th_warn = warning_thresholds; | ||
288 | th_crit = critical_thresholds; | ||
289 | for (size_t i = 0; i < numoids; i++) { | ||
290 | char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL; | ||
291 | char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL; | ||
292 | /* translate "2:1" to "@1:2" for backwards compatibility */ | ||
293 | w = w ? fix_snmp_range(w) : NULL; | ||
294 | c = c ? fix_snmp_range(c) : NULL; | ||
295 | |||
296 | while (i >= thlds_size) { | ||
297 | thlds_size += OID_COUNT_STEP; | ||
298 | thlds = realloc(thlds, thlds_size * sizeof(*thlds)); | ||
299 | } | ||
300 | |||
301 | /* Skip empty thresholds, while avoiding segfault */ | ||
302 | set_thresholds(&thlds[i], w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL); | ||
303 | if (w) { | ||
304 | th_warn = strchr(th_warn, ','); | ||
305 | if (th_warn) | ||
306 | th_warn++; | ||
307 | free(w); | ||
308 | } | ||
309 | if (c) { | ||
310 | th_crit = strchr(th_crit, ','); | ||
311 | if (th_crit) | ||
312 | th_crit++; | ||
313 | free(c); | ||
314 | } | ||
315 | } | ||
316 | 277 | ||
317 | /* Create the command array to execute */ | 278 | if (config.output_format_is_set) { |
318 | if (usesnmpgetnext) { | 279 | mp_set_format(config.output_format); |
319 | snmpcmd = strdup(PATH_TO_SNMPGETNEXT); | ||
320 | } else { | ||
321 | snmpcmd = strdup(PATH_TO_SNMPGET); | ||
322 | } | 280 | } |
323 | 281 | ||
324 | /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ | 282 | /* Set signal handling and alarm */ |
325 | 283 | if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { | |
326 | unsigned index = 0; | 284 | usage4(_("Cannot catch SIGALRM")); |
327 | command_line = calloc(11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof(char *)); | ||
328 | |||
329 | command_line[index++] = snmpcmd; | ||
330 | command_line[index++] = strdup("-Le"); | ||
331 | command_line[index++] = strdup("-t"); | ||
332 | xasprintf(&command_line[index++], "%d", timeout_interval); | ||
333 | command_line[index++] = strdup("-r"); | ||
334 | xasprintf(&command_line[index++], "%d", retries); | ||
335 | command_line[index++] = strdup("-m"); | ||
336 | command_line[index++] = strdup(miblist); | ||
337 | command_line[index++] = "-v"; | ||
338 | command_line[index++] = strdup(proto); | ||
339 | |||
340 | xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", | ||
341 | proto); | ||
342 | |||
343 | if (ignore_mib_parsing_errors) { | ||
344 | command_line[index++] = "-Pe"; | ||
345 | xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth); | ||
346 | } | 285 | } |
347 | 286 | ||
348 | for (int i = 0; i < numcontext; i++) { | 287 | time_t current_time; |
349 | command_line[index++] = contextargs[i]; | 288 | time(¤t_time); |
350 | } | ||
351 | 289 | ||
352 | for (int i = 0; i < numauthpriv; i++) { | 290 | if (verbose > 2) { |
353 | command_line[index++] = authpriv[i]; | 291 | printf("current time: %s (timestamp: %lu)\n", ctime(¤t_time), current_time); |
354 | } | 292 | } |
355 | 293 | ||
356 | xasprintf(&command_line[index++], "%s:%s", server_address, port); | 294 | snmp_responces response = do_snmp_query(config.snmp_params); |
357 | 295 | ||
358 | xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", cl_hidden_auth, server_address, port); | 296 | mp_check overall = mp_check_init(); |
359 | 297 | ||
360 | for (size_t i = 0; i < numoids; i++) { | 298 | if (response.errorcode == OK) { |
361 | command_line[index++] = oids[i]; | 299 | mp_subcheck sc_successfull_query = mp_subcheck_init(); |
362 | xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]); | 300 | xasprintf(&sc_successfull_query.output, "SNMP query was successful"); |
301 | sc_successfull_query = mp_set_subcheck_state(sc_successfull_query, STATE_OK); | ||
302 | mp_add_subcheck_to_check(&overall, sc_successfull_query); | ||
303 | } else { | ||
304 | // Error treatment here, either partial or whole | ||
305 | mp_subcheck sc_failed_query = mp_subcheck_init(); | ||
306 | xasprintf(&sc_failed_query.output, "SNMP query failed"); | ||
307 | sc_failed_query = mp_set_subcheck_state(sc_failed_query, STATE_OK); | ||
308 | mp_add_subcheck_to_check(&overall, sc_failed_query); | ||
309 | mp_exit(overall); | ||
363 | } | 310 | } |
364 | 311 | ||
365 | command_line[index++] = NULL; | 312 | check_snmp_state_entry *prev_state = NULL; |
313 | bool have_previous_state = false; | ||
366 | 314 | ||
367 | if (verbose) { | 315 | if (config.evaluation_params.calculate_rate) { |
368 | printf("%s\n", cl_hidden_auth); | 316 | state_data *previous_state = np_state_read(stateKey); |
369 | } | 317 | if (previous_state == NULL) { |
318 | // failed to recover state | ||
319 | // or no previous state | ||
320 | have_previous_state = false; | ||
321 | } else { | ||
322 | // sanity check | ||
323 | recover_state_data_type prev_state_wrapper = | ||
324 | recover_state_data(previous_state->data, (idx_t)previous_state->length); | ||
370 | 325 | ||
371 | /* Set signal handling and alarm */ | 326 | if (prev_state_wrapper.errorcode == OK) { |
372 | if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { | 327 | have_previous_state = true; |
373 | usage4(_("Cannot catch SIGALRM")); | 328 | prev_state = prev_state_wrapper.state; |
374 | } | 329 | } else { |
375 | alarm(timeout_interval * retries + 5); | 330 | have_previous_state = false; |
376 | 331 | prev_state = NULL; | |
377 | /* Run the command */ | ||
378 | return_code = cmd_run_array(command_line, &chld_out, &chld_err, 0); | ||
379 | |||
380 | /* disable alarm again */ | ||
381 | alarm(0); | ||
382 | |||
383 | /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs, | ||
384 | only return state unknown if return code is non zero or there is no stdout. | ||
385 | Do this way so that if there is stderr, will get added to output, which helps problem diagnosis | ||
386 | */ | ||
387 | if (return_code != 0) | ||
388 | external_error = 1; | ||
389 | if (chld_out.lines == 0) | ||
390 | external_error = 1; | ||
391 | if (external_error) { | ||
392 | if (chld_err.lines > 0) { | ||
393 | printf(_("External command error: %s\n"), chld_err.line[0]); | ||
394 | for (size_t i = 1; i < chld_err.lines; i++) { | ||
395 | printf("%s\n", chld_err.line[i]); | ||
396 | } | 332 | } |
397 | } else { | ||
398 | printf(_("External command error with no output (return code: %d)\n"), return_code); | ||
399 | } | 333 | } |
400 | exit(STATE_UNKNOWN); | ||
401 | } | 334 | } |
402 | 335 | ||
403 | if (verbose) { | 336 | check_snmp_state_entry *new_state = NULL; |
404 | for (size_t i = 0; i < chld_out.lines; i++) { | 337 | if (config.evaluation_params.calculate_rate) { |
405 | printf("%s\n", chld_out.line[i]); | 338 | new_state = calloc(config.snmp_params.num_of_test_units, sizeof(check_snmp_state_entry)); |
339 | if (new_state == NULL) { | ||
340 | die(STATE_UNKNOWN, "memory allocation failed"); | ||
406 | } | 341 | } |
407 | } | 342 | } |
408 | 343 | ||
409 | line = 0; | 344 | // We got the the query results, now process them |
410 | total_oids = 0; | 345 | for (size_t loop_index = 0; loop_index < config.snmp_params.num_of_test_units; loop_index++) { |
411 | for (size_t i = 0; line < chld_out.lines && i < numoids; line++, i++, total_oids++) { | 346 | if (verbose > 0) { |
412 | if (calculate_rate) | 347 | printf("loop_index: %zu\n", loop_index); |
413 | conv = "%.10g"; | ||
414 | else | ||
415 | conv = "%.0f"; | ||
416 | |||
417 | ptr = chld_out.line[line]; | ||
418 | oidname = strpcpy(oidname, ptr, delimiter); | ||
419 | response = strstr(ptr, delimiter); | ||
420 | if (response == NULL) | ||
421 | break; | ||
422 | |||
423 | if (verbose > 2) { | ||
424 | printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i + 1, line + 1, oidname, response); | ||
425 | } | 348 | } |
426 | 349 | ||
427 | /* Clean up type array - Sol10 does not necessarily zero it out */ | 350 | check_snmp_state_entry previous_unit_state = {}; |
428 | bzero(type, sizeof(type)); | 351 | if (config.evaluation_params.calculate_rate && have_previous_state) { |
429 | 352 | previous_unit_state = prev_state[loop_index]; | |
430 | is_counter = 0; | 353 | } |
431 | /* We strip out the datatype indicator for PHBs */ | ||
432 | if (strstr(response, "Gauge: ")) { | ||
433 | show = multiply(strstr(response, "Gauge: ") + 7); | ||
434 | } else if (strstr(response, "Gauge32: ")) { | ||
435 | show = multiply(strstr(response, "Gauge32: ") + 9); | ||
436 | } else if (strstr(response, "Counter32: ")) { | ||
437 | show = strstr(response, "Counter32: ") + 11; | ||
438 | is_counter = 1; | ||
439 | if (!calculate_rate) | ||
440 | strcpy(type, "c"); | ||
441 | } else if (strstr(response, "Counter64: ")) { | ||
442 | show = strstr(response, "Counter64: ") + 11; | ||
443 | is_counter = 1; | ||
444 | if (!calculate_rate) | ||
445 | strcpy(type, "c"); | ||
446 | } else if (strstr(response, "INTEGER: ")) { | ||
447 | show = multiply(strstr(response, "INTEGER: ") + 9); | ||
448 | |||
449 | if (fmtstr_set) { | ||
450 | conv = fmtstr; | ||
451 | } | ||
452 | } else if (strstr(response, "OID: ")) { | ||
453 | show = strstr(response, "OID: ") + 5; | ||
454 | } else if (strstr(response, "STRING: ")) { | ||
455 | show = strstr(response, "STRING: ") + 8; | ||
456 | conv = "%.10g"; | ||
457 | |||
458 | /* Get the rest of the string on multi-line strings */ | ||
459 | ptr = show; | ||
460 | COUNT_SEQ(ptr, bk_count, dq_count) | ||
461 | while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') { | ||
462 | ptr++; | ||
463 | GOBBLE_TOS(ptr, "\n\"\\") | ||
464 | COUNT_SEQ(ptr, bk_count, dq_count) | ||
465 | } | ||
466 | |||
467 | if (dq_count) { /* unfinished line */ | ||
468 | /* copy show verbatim first */ | ||
469 | if (!mult_resp) | ||
470 | mult_resp = strdup(""); | ||
471 | xasprintf(&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show); | ||
472 | /* then strip out unmatched double-quote from single-line output */ | ||
473 | if (show[0] == '"') | ||
474 | show++; | ||
475 | |||
476 | /* Keep reading until we match end of double-quoted string */ | ||
477 | for (line++; line < chld_out.lines; line++) { | ||
478 | ptr = chld_out.line[line]; | ||
479 | xasprintf(&mult_resp, "%s%s\n", mult_resp, ptr); | ||
480 | |||
481 | COUNT_SEQ(ptr, bk_count, dq_count) | ||
482 | while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') { | ||
483 | ptr++; | ||
484 | GOBBLE_TOS(ptr, "\n\"\\") | ||
485 | COUNT_SEQ(ptr, bk_count, dq_count) | ||
486 | } | ||
487 | /* Break for loop before next line increment when done */ | ||
488 | if (!dq_count) | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | } else if (strstr(response, "Timeticks: ")) { | ||
494 | show = strstr(response, "Timeticks: "); | ||
495 | } else | ||
496 | show = response + 3; | ||
497 | 354 | ||
498 | iresult = STATE_DEPENDENT; | 355 | check_snmp_evaluation single_eval = |
356 | evaluate_single_unit(response.response_values[loop_index], config.evaluation_params, | ||
357 | config.snmp_params.test_units[loop_index], current_time, | ||
358 | previous_unit_state, have_previous_state); | ||
499 | 359 | ||
500 | /* Process this block for numeric comparisons */ | 360 | if (config.evaluation_params.calculate_rate && |
501 | /* Make some special values,like Timeticks numeric only if a threshold is defined */ | 361 | mp_compute_subcheck_state(single_eval.sc) != STATE_UNKNOWN) { |
502 | if (thlds[i]->warning || thlds[i]->critical || calculate_rate) { | 362 | new_state[loop_index] = single_eval.state; |
503 | if (verbose > 2) { | ||
504 | print_thresholds(" thresholds", thlds[i]); | ||
505 | } | ||
506 | ptr = strpbrk(show, "-0123456789"); | ||
507 | if (ptr == NULL) { | ||
508 | if (nulloid == 3) | ||
509 | die(STATE_UNKNOWN, _("No valid data returned (%s)\n"), show); | ||
510 | else if (nulloid == 0) | ||
511 | die(STATE_OK, _("No valid data returned (%s)\n"), show); | ||
512 | else if (nulloid == 1) | ||
513 | die(STATE_WARNING, _("No valid data returned (%s)\n"), show); | ||
514 | else if (nulloid == 2) | ||
515 | die(STATE_CRITICAL, _("No valid data returned (%s)\n"), show); | ||
516 | } | ||
517 | while (i >= response_size) { | ||
518 | response_size += OID_COUNT_STEP; | ||
519 | response_value = realloc(response_value, response_size * sizeof(*response_value)); | ||
520 | } | ||
521 | response_value[i] = strtod(ptr, NULL) + offset; | ||
522 | |||
523 | if (calculate_rate) { | ||
524 | if (previous_state != NULL) { | ||
525 | duration = current_time - previous_state->time; | ||
526 | if (duration <= 0) | ||
527 | die(STATE_UNKNOWN, _("Time duration between plugin calls is invalid")); | ||
528 | temp_double = response_value[i] - previous_value[i]; | ||
529 | /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */ | ||
530 | if (is_counter) { | ||
531 | if (temp_double < (double)0.0) | ||
532 | temp_double += (double)4294967296.0; /* 2^32 */ | ||
533 | if (temp_double < (double)0.0) | ||
534 | temp_double += (double)18446744069414584320.0; /* 2^64-2^32 */ | ||
535 | ; | ||
536 | } | ||
537 | /* Convert to per second, then use multiplier */ | ||
538 | temp_double = temp_double / duration * rate_multiplier; | ||
539 | iresult = get_status(temp_double, thlds[i]); | ||
540 | xasprintf(&show, conv, temp_double); | ||
541 | } | ||
542 | } else { | ||
543 | iresult = get_status(response_value[i], thlds[i]); | ||
544 | xasprintf(&show, conv, response_value[i]); | ||
545 | } | ||
546 | } | 363 | } |
547 | 364 | ||
548 | /* Process this block for string matching */ | 365 | mp_add_subcheck_to_check(&overall, single_eval.sc); |
549 | else if (eval_size > i && eval_method[i] & CRIT_STRING) { | 366 | } |
550 | if (strcmp(show, string_value)) | ||
551 | iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK; | ||
552 | else | ||
553 | iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL; | ||
554 | } | ||
555 | 367 | ||
556 | /* Process this block for regex matching */ | 368 | if (config.evaluation_params.calculate_rate) { |
557 | else if (eval_size > i && eval_method[i] & CRIT_REGEX) { | 369 | // store state |
558 | excode = regexec(&preg, response, 10, pmatch, eflags); | 370 | gen_state_string_type current_state_wrapper = |
559 | if (excode == 0) { | 371 | gen_state_string(new_state, config.snmp_params.num_of_test_units); |
560 | iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL; | ||
561 | } else if (excode != REG_NOMATCH) { | ||
562 | regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
563 | printf(_("Execute Error: %s\n"), errbuf); | ||
564 | exit(STATE_CRITICAL); | ||
565 | } else { | ||
566 | iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK; | ||
567 | } | ||
568 | } | ||
569 | 372 | ||
570 | /* Process this block for existence-nonexistence checks */ | 373 | if (current_state_wrapper.errorcode == OK) { |
571 | /* TV: Should this be outside of this else block? */ | 374 | np_state_write_string(stateKey, current_time, current_state_wrapper.state_string); |
572 | else { | 375 | } else { |
573 | if (eval_size > i && eval_method[i] & CRIT_PRESENT) | 376 | die(STATE_UNKNOWN, "failed to create state string"); |
574 | iresult = STATE_CRITICAL; | ||
575 | else if (eval_size > i && eval_method[i] & WARN_PRESENT) | ||
576 | iresult = STATE_WARNING; | ||
577 | else if (response && iresult == STATE_DEPENDENT) | ||
578 | iresult = STATE_OK; | ||
579 | } | 377 | } |
378 | } | ||
379 | mp_exit(overall); | ||
380 | } | ||
580 | 381 | ||
581 | /* Result is the worst outcome of all the OIDs tested */ | 382 | /* process command-line arguments */ |
582 | result = max_state(result, iresult); | 383 | static process_arguments_wrapper process_arguments(int argc, char **argv) { |
583 | 384 | enum { | |
584 | /* Prepend a label for this OID if there is one */ | 385 | /* Longopts only arguments */ |
585 | if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) | 386 | invert_search_index = CHAR_MAX + 1, |
586 | xasprintf(&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark(iresult), show, mark(iresult)); | 387 | offset_index, |
587 | else | 388 | ignore_mib_parsing_errors_index, |
588 | xasprintf(&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, mark(iresult), show, mark(iresult)); | 389 | connection_prefix_index, |
589 | 390 | output_format_index, | |
590 | /* Append a unit string for this OID if there is one */ | 391 | calculate_rate, |
591 | if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL) | 392 | rate_multiplier |
592 | xasprintf(&outbuff, "%s %s", outbuff, unitv[i]); | 393 | }; |
593 | 394 | ||
594 | /* Write perfdata with whatever can be parsed by strtod, if possible */ | 395 | static struct option longopts[] = { |
595 | ptr = NULL; | 396 | STD_LONG_OPTS, |
596 | strtod(show, &ptr); | 397 | {"community", required_argument, 0, 'C'}, |
597 | if (ptr > show) { | 398 | {"oid", required_argument, 0, 'o'}, |
598 | if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) | 399 | {"object", required_argument, 0, 'o'}, |
599 | temp_string = labels[i]; | 400 | {"delimiter", required_argument, 0, 'd'}, |
600 | else | 401 | {"nulloid", required_argument, 0, 'z'}, |
601 | temp_string = oidname; | 402 | {"output-delimiter", required_argument, 0, 'D'}, |
602 | if (strpbrk(temp_string, " ='\"") == NULL) { | 403 | {"string", required_argument, 0, 's'}, |
603 | strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1); | 404 | {"timeout", required_argument, 0, 't'}, |
604 | } else { | 405 | {"regex", required_argument, 0, 'r'}, |
605 | if (strpbrk(temp_string, "'") == NULL) { | 406 | {"ereg", required_argument, 0, 'r'}, |
606 | quote_string = "'"; | 407 | {"eregi", required_argument, 0, 'R'}, |
607 | } else { | 408 | {"label", required_argument, 0, 'l'}, |
608 | quote_string = "\""; | 409 | {"units", required_argument, 0, 'u'}, |
609 | } | 410 | {"port", required_argument, 0, 'p'}, |
610 | strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1); | 411 | {"retries", required_argument, 0, 'e'}, |
611 | strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1); | 412 | {"miblist", required_argument, 0, 'm'}, |
612 | strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1); | 413 | {"protocol", required_argument, 0, 'P'}, |
613 | } | 414 | {"context", required_argument, 0, 'N'}, |
614 | strncat(perfstr, "=", sizeof(perfstr) - strlen(perfstr) - 1); | 415 | {"seclevel", required_argument, 0, 'L'}, |
615 | len = sizeof(perfstr) - strlen(perfstr) - 1; | 416 | {"secname", required_argument, 0, 'U'}, |
616 | strncat(perfstr, show, len > ptr - show ? ptr - show : len); | 417 | {"authproto", required_argument, 0, 'a'}, |
418 | {"privproto", required_argument, 0, 'x'}, | ||
419 | {"authpasswd", required_argument, 0, 'A'}, | ||
420 | {"privpasswd", required_argument, 0, 'X'}, | ||
421 | {"next", no_argument, 0, 'n'}, | ||
422 | {"offset", required_argument, 0, offset_index}, | ||
423 | {"invert-search", no_argument, 0, invert_search_index}, | ||
424 | {"perf-oids", no_argument, 0, 'O'}, | ||
425 | {"ipv4", no_argument, 0, '4'}, | ||
426 | {"ipv6", no_argument, 0, '6'}, | ||
427 | {"multiplier", required_argument, 0, 'M'}, | ||
428 | {"ignore-mib-parsing-errors", no_argument, 0, ignore_mib_parsing_errors_index}, | ||
429 | {"connection-prefix", required_argument, 0, connection_prefix_index}, | ||
430 | {"output-format", required_argument, 0, output_format_index}, | ||
431 | {"rate", no_argument, 0, calculate_rate}, | ||
432 | {"rate-multiplier", required_argument, 0, rate_multiplier}, | ||
433 | {0, 0, 0, 0}}; | ||
434 | |||
435 | if (argc < 2) { | ||
436 | process_arguments_wrapper result = { | ||
437 | .errorcode = ERROR, | ||
438 | }; | ||
439 | return result; | ||
440 | } | ||
617 | 441 | ||
618 | if (strcmp(type, "") != 0) { | 442 | // Count number of OIDs here first |
619 | strncat(perfstr, type, sizeof(perfstr) - strlen(perfstr) - 1); | 443 | int option = 0; |
620 | } | 444 | size_t oid_counter = 0; |
445 | while (true) { | ||
446 | int option_char = getopt_long( | ||
447 | argc, argv, | ||
448 | "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option); | ||
621 | 449 | ||
622 | if (warning_thresholds) { | 450 | if (option_char == -1 || option_char == EOF) { |
623 | strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); | 451 | break; |
624 | if (thlds[i]->warning && thlds[i]->warning->text) | 452 | } |
625 | strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr) - strlen(perfstr) - 1); | ||
626 | } | ||
627 | 453 | ||
628 | if (critical_thresholds) { | 454 | switch (option_char) { |
629 | if (!warning_thresholds) | 455 | case 'o': { |
630 | strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); | 456 | // we are going to parse this again, so we work on a copy of that string |
631 | strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1); | 457 | char *tmp_oids = strdup(optarg); |
632 | if (thlds[i]->critical && thlds[i]->critical->text) | 458 | if (tmp_oids == NULL) { |
633 | strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr) - strlen(perfstr) - 1); | 459 | die(STATE_UNKNOWN, "strdup failed"); |
634 | } | 460 | } |
635 | 461 | ||
636 | strncat(perfstr, " ", sizeof(perfstr) - strlen(perfstr) - 1); | 462 | for (char *ptr = strtok(tmp_oids, ", "); ptr != NULL; |
637 | } | 463 | ptr = strtok(NULL, ", "), oid_counter++) { |
638 | } | ||
639 | |||
640 | /* Save state data, as all data collected now */ | ||
641 | if (calculate_rate) { | ||
642 | string_length = 1024; | ||
643 | state_string = malloc(string_length); | ||
644 | if (state_string == NULL) | ||
645 | die(STATE_UNKNOWN, _("Cannot malloc")); | ||
646 | |||
647 | current_length = 0; | ||
648 | for (int i = 0; i < total_oids; i++) { | ||
649 | xasprintf(&temp_string, "%.0f", response_value[i]); | ||
650 | if (temp_string == NULL) | ||
651 | die(STATE_UNKNOWN, _("Cannot asprintf()")); | ||
652 | response_length = strlen(temp_string); | ||
653 | if (current_length + response_length > string_length) { | ||
654 | string_length = current_length + 1024; | ||
655 | state_string = realloc(state_string, string_length); | ||
656 | if (state_string == NULL) | ||
657 | die(STATE_UNKNOWN, _("Cannot realloc()")); | ||
658 | } | 464 | } |
659 | strcpy(&state_string[current_length], temp_string); | 465 | break; |
660 | current_length = current_length + response_length; | ||
661 | state_string[current_length] = ':'; | ||
662 | current_length++; | ||
663 | free(temp_string); | ||
664 | } | 466 | } |
665 | state_string[--current_length] = '\0'; | 467 | case '?': /* usage */ |
666 | if (verbose > 2) | 468 | usage5(); |
667 | printf("State string=%s\n", state_string); | 469 | // fallthrough |
470 | case 'h': /* help */ | ||
471 | print_help(); | ||
472 | exit(STATE_UNKNOWN); | ||
473 | case 'V': /* version */ | ||
474 | print_revision(progname, NP_VERSION); | ||
475 | exit(STATE_UNKNOWN); | ||
668 | 476 | ||
669 | /* This is not strictly the same as time now, but any subtle variations will cancel out */ | 477 | default: |
670 | np_state_write_string(current_time, state_string); | 478 | continue; |
671 | if (previous_state == NULL) { | ||
672 | /* Or should this be highest state? */ | ||
673 | die(STATE_OK, _("No previous data to calculate rate - assume okay")); | ||
674 | } | 479 | } |
675 | } | 480 | } |
676 | 481 | ||
677 | printf("%s %s -%s %s\n", label, state_text(result), outbuff, perfstr); | 482 | /* Check whether at least one OID was given */ |
678 | if (mult_resp) | 483 | if (oid_counter == 0) { |
679 | printf("%s", mult_resp); | 484 | die(STATE_UNKNOWN, _("No OIDs specified\n")); |
485 | } | ||
680 | 486 | ||
681 | return result; | 487 | // Allocate space for test units |
682 | } | 488 | check_snmp_test_unit *tmp = calloc(oid_counter, sizeof(check_snmp_test_unit)); |
489 | if (tmp == NULL) { | ||
490 | die(STATE_UNKNOWN, "Failed to calloc"); | ||
491 | } | ||
683 | 492 | ||
684 | /* process command-line arguments */ | 493 | for (size_t i = 0; i < oid_counter; i++) { |
685 | int process_arguments(int argc, char **argv) { | 494 | tmp[i] = check_snmp_test_unit_init(); |
686 | static struct option longopts[] = {STD_LONG_OPTS, | ||
687 | {"community", required_argument, 0, 'C'}, | ||
688 | {"oid", required_argument, 0, 'o'}, | ||
689 | {"object", required_argument, 0, 'o'}, | ||
690 | {"delimiter", required_argument, 0, 'd'}, | ||
691 | {"nulloid", required_argument, 0, 'z'}, | ||
692 | {"output-delimiter", required_argument, 0, 'D'}, | ||
693 | {"string", required_argument, 0, 's'}, | ||
694 | {"timeout", required_argument, 0, 't'}, | ||
695 | {"regex", required_argument, 0, 'r'}, | ||
696 | {"ereg", required_argument, 0, 'r'}, | ||
697 | {"eregi", required_argument, 0, 'R'}, | ||
698 | {"label", required_argument, 0, 'l'}, | ||
699 | {"units", required_argument, 0, 'u'}, | ||
700 | {"port", required_argument, 0, 'p'}, | ||
701 | {"retries", required_argument, 0, 'e'}, | ||
702 | {"miblist", required_argument, 0, 'm'}, | ||
703 | {"protocol", required_argument, 0, 'P'}, | ||
704 | {"context", required_argument, 0, 'N'}, | ||
705 | {"seclevel", required_argument, 0, 'L'}, | ||
706 | {"secname", required_argument, 0, 'U'}, | ||
707 | {"authproto", required_argument, 0, 'a'}, | ||
708 | {"privproto", required_argument, 0, 'x'}, | ||
709 | {"authpasswd", required_argument, 0, 'A'}, | ||
710 | {"privpasswd", required_argument, 0, 'X'}, | ||
711 | {"next", no_argument, 0, 'n'}, | ||
712 | {"rate", no_argument, 0, L_CALCULATE_RATE}, | ||
713 | {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, | ||
714 | {"offset", required_argument, 0, L_OFFSET}, | ||
715 | {"invert-search", no_argument, 0, L_INVERT_SEARCH}, | ||
716 | {"perf-oids", no_argument, 0, 'O'}, | ||
717 | {"ipv4", no_argument, 0, '4'}, | ||
718 | {"ipv6", no_argument, 0, '6'}, | ||
719 | {"multiplier", required_argument, 0, 'M'}, | ||
720 | {"fmtstr", required_argument, 0, 'f'}, | ||
721 | {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS}, | ||
722 | {0, 0, 0, 0}}; | ||
723 | |||
724 | if (argc < 2) | ||
725 | return ERROR; | ||
726 | |||
727 | /* reverse compatibility for very old non-POSIX usage forms */ | ||
728 | for (int c = 1; c < argc; c++) { | ||
729 | if (strcmp("-to", argv[c]) == 0) | ||
730 | strcpy(argv[c], "-t"); | ||
731 | if (strcmp("-wv", argv[c]) == 0) | ||
732 | strcpy(argv[c], "-w"); | ||
733 | if (strcmp("-cv", argv[c]) == 0) | ||
734 | strcpy(argv[c], "-c"); | ||
735 | } | 495 | } |
736 | 496 | ||
737 | size_t j = 0; | 497 | check_snmp_config config = check_snmp_config_init(); |
738 | size_t jj = 0; | 498 | config.snmp_params.test_units = tmp; |
499 | config.snmp_params.num_of_test_units = oid_counter; | ||
500 | |||
501 | option = 0; | ||
502 | optind = 1; // Reset argument scanner | ||
503 | size_t tmp_oid_counter = 0; | ||
504 | size_t eval_counter = 0; | ||
505 | size_t unitv_counter = 0; | ||
506 | size_t labels_counter = 0; | ||
507 | unsigned char *authpasswd = NULL; | ||
508 | unsigned char *privpasswd = NULL; | ||
509 | int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; | ||
510 | char *port = NULL; | ||
511 | char *miblist = NULL; | ||
512 | char *connection_prefix = NULL; | ||
513 | bool snmp_version_set_explicitely = false; | ||
514 | // TODO error checking | ||
739 | while (true) { | 515 | while (true) { |
740 | int option = 0; | 516 | int option_char = getopt_long( |
741 | int option_char = getopt_long(argc, argv, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option); | 517 | argc, argv, |
518 | "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option); | ||
742 | 519 | ||
743 | if (option_char == -1 || option_char == EOF) | 520 | if (option_char == -1 || option_char == EOF) { |
744 | break; | 521 | break; |
522 | } | ||
745 | 523 | ||
746 | switch (option_char) { | 524 | switch (option_char) { |
747 | case '?': /* usage */ | 525 | case '?': /* usage */ |
@@ -758,64 +536,155 @@ int process_arguments(int argc, char **argv) { | |||
758 | 536 | ||
759 | /* Connection info */ | 537 | /* Connection info */ |
760 | case 'C': /* group or community */ | 538 | case 'C': /* group or community */ |
761 | community = optarg; | 539 | config.snmp_params.snmp_session.community = (unsigned char *)optarg; |
540 | config.snmp_params.snmp_session.community_len = strlen(optarg); | ||
762 | break; | 541 | break; |
763 | case 'H': /* Host or server */ | 542 | case 'H': /* Host or server */ |
764 | server_address = optarg; | 543 | config.snmp_params.snmp_session.peername = optarg; |
765 | break; | 544 | break; |
766 | case 'p': /* TCP port number */ | 545 | case 'p': /*port number */ |
546 | // Add port to "peername" below to not rely on argument order | ||
767 | port = optarg; | 547 | port = optarg; |
768 | break; | 548 | break; |
769 | case 'm': /* List of MIBS */ | 549 | case 'm': /* List of MIBS */ |
770 | miblist = optarg; | 550 | miblist = optarg; |
771 | break; | 551 | break; |
772 | case 'n': /* usesnmpgetnext */ | 552 | case 'n': /* use_getnext instead of get */ |
773 | usesnmpgetnext = true; | 553 | config.snmp_params.use_getnext = true; |
774 | break; | 554 | break; |
775 | case 'P': /* SNMP protocol version */ | 555 | case 'P': /* SNMP protocol version */ |
776 | proto = optarg; | 556 | if (strcasecmp("1", optarg) == 0) { |
557 | config.snmp_params.snmp_session.version = SNMP_VERSION_1; | ||
558 | } else if (strcasecmp("2c", optarg) == 0) { | ||
559 | config.snmp_params.snmp_session.version = SNMP_VERSION_2c; | ||
560 | } else if (strcasecmp("3", optarg) == 0) { | ||
561 | config.snmp_params.snmp_session.version = SNMP_VERSION_3; | ||
562 | } else { | ||
563 | die(STATE_UNKNOWN, "invalid SNMP version/protocol: %s", optarg); | ||
564 | } | ||
565 | snmp_version_set_explicitely = true; | ||
566 | |||
777 | break; | 567 | break; |
778 | case 'N': /* SNMPv3 context */ | 568 | case 'N': /* SNMPv3 context name */ |
779 | context = optarg; | 569 | config.snmp_params.snmp_session.contextName = optarg; |
570 | config.snmp_params.snmp_session.contextNameLen = strlen(optarg); | ||
780 | break; | 571 | break; |
781 | case 'L': /* security level */ | 572 | case 'L': /* security level */ |
782 | seclevel = optarg; | 573 | if (strcasecmp("noAuthNoPriv", optarg) == 0) { |
574 | config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH; | ||
575 | } else if (strcasecmp("authNoPriv", optarg) == 0) { | ||
576 | config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; | ||
577 | } else if (strcasecmp("authPriv", optarg) == 0) { | ||
578 | config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; | ||
579 | } else { | ||
580 | die(STATE_UNKNOWN, "invalid security level: %s", optarg); | ||
581 | } | ||
783 | break; | 582 | break; |
784 | case 'U': /* security username */ | 583 | case 'U': /* security username */ |
785 | secname = optarg; | 584 | config.snmp_params.snmp_session.securityName = optarg; |
585 | config.snmp_params.snmp_session.securityNameLen = strlen(optarg); | ||
786 | break; | 586 | break; |
787 | case 'a': /* auth protocol */ | 587 | case 'a': /* auth protocol */ |
788 | authproto = optarg; | 588 | // SNMPv3: SHA or MD5 |
589 | // TODO Test for availability of individual protocols | ||
590 | if (strcasecmp("MD5", optarg) == 0) { | ||
591 | config.snmp_params.snmp_session.securityAuthProto = usmHMACMD5AuthProtocol; | ||
592 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
593 | OID_LENGTH(usmHMACMD5AuthProtocol); | ||
594 | } else if (strcasecmp("SHA", optarg) == 0) { | ||
595 | config.snmp_params.snmp_session.securityAuthProto = usmHMACSHA1AuthProtocol; | ||
596 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
597 | OID_LENGTH(usmHMACSHA1AuthProtocol); | ||
598 | } else if (strcasecmp("SHA224", optarg) == 0) { | ||
599 | config.snmp_params.snmp_session.securityAuthProto = usmHMAC128SHA224AuthProtocol; | ||
600 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
601 | OID_LENGTH(usmHMAC128SHA224AuthProtocol); | ||
602 | } else if (strcasecmp("SHA256", optarg) == 0) { | ||
603 | config.snmp_params.snmp_session.securityAuthProto = usmHMAC192SHA256AuthProtocol; | ||
604 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
605 | OID_LENGTH(usmHMAC192SHA256AuthProtocol); | ||
606 | } else if (strcasecmp("SHA384", optarg) == 0) { | ||
607 | config.snmp_params.snmp_session.securityAuthProto = usmHMAC256SHA384AuthProtocol; | ||
608 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
609 | OID_LENGTH(usmHMAC256SHA384AuthProtocol); | ||
610 | } else if (strcasecmp("SHA512", optarg) == 0) { | ||
611 | config.snmp_params.snmp_session.securityAuthProto = usmHMAC384SHA512AuthProtocol; | ||
612 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
613 | OID_LENGTH(usmHMAC384SHA512AuthProtocol); | ||
614 | } else { | ||
615 | die(STATE_UNKNOWN, "Unknown authentication protocol"); | ||
616 | } | ||
789 | break; | 617 | break; |
790 | case 'x': /* priv protocol */ | 618 | case 'x': /* priv protocol */ |
791 | privproto = optarg; | 619 | if (strcasecmp("DES", optarg) == 0) { |
620 | #ifdef HAVE_USM_DES_PRIV_PROTOCOL | ||
621 | config.snmp_params.snmp_session.securityAuthProto = usmDESPrivProtocol; | ||
622 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
623 | OID_LENGTH(usmDESPrivProtocol); | ||
624 | #else | ||
625 | die(STATE_UNKNOWN, "DES Privacy Protocol not available on this platform"); | ||
626 | #endif | ||
627 | } else if (strcasecmp("AES", optarg) == 0) { | ||
628 | config.snmp_params.snmp_session.securityAuthProto = usmAESPrivProtocol; | ||
629 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
630 | OID_LENGTH(usmAESPrivProtocol); | ||
631 | // } else if (strcasecmp("AES128", optarg)) { | ||
632 | // config.snmp_session.securityAuthProto = usmAES128PrivProtocol; | ||
633 | // config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES128PrivProtocol) | ||
634 | // / OID_LENGTH(oid); | ||
635 | } else if (strcasecmp("AES192", optarg) == 0) { | ||
636 | config.snmp_params.snmp_session.securityAuthProto = usmAES192PrivProtocol; | ||
637 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
638 | OID_LENGTH(usmAES192PrivProtocol); | ||
639 | } else if (strcasecmp("AES256", optarg) == 0) { | ||
640 | config.snmp_params.snmp_session.securityAuthProto = usmAES256PrivProtocol; | ||
641 | config.snmp_params.snmp_session.securityAuthProtoLen = | ||
642 | OID_LENGTH(usmAES256PrivProtocol); | ||
643 | // } else if (strcasecmp("AES192Cisco", optarg)) { | ||
644 | // config.snmp_session.securityAuthProto = usmAES192CiscoPrivProtocol; | ||
645 | // config.snmp_session.securityAuthProtoLen = | ||
646 | // sizeof(usmAES192CiscoPrivProtocol) / sizeof(oid); } else if | ||
647 | // (strcasecmp("AES256Cisco", optarg)) { config.snmp_session.securityAuthProto = | ||
648 | // usmAES256CiscoPrivProtocol; config.snmp_session.securityAuthProtoLen = | ||
649 | // sizeof(usmAES256CiscoPrivProtocol) / sizeof(oid); } else if | ||
650 | // (strcasecmp("AES192Cisco2", optarg)) { config.snmp_session.securityAuthProto | ||
651 | // = usmAES192Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen = | ||
652 | // sizeof(usmAES192Cisco2PrivProtocol) / sizeof(oid); } else if | ||
653 | // (strcasecmp("AES256Cisco2", optarg)) { config.snmp_session.securityAuthProto | ||
654 | // = usmAES256Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen = | ||
655 | // sizeof(usmAES256Cisco2PrivProtocol) / sizeof(oid); | ||
656 | } else { | ||
657 | die(STATE_UNKNOWN, "Unknown privacy protocol"); | ||
658 | } | ||
792 | break; | 659 | break; |
793 | case 'A': /* auth passwd */ | 660 | case 'A': /* auth passwd */ |
794 | authpasswd = optarg; | 661 | authpasswd = (unsigned char *)optarg; |
795 | break; | 662 | break; |
796 | case 'X': /* priv passwd */ | 663 | case 'X': /* priv passwd */ |
797 | privpasswd = optarg; | 664 | privpasswd = (unsigned char *)optarg; |
665 | break; | ||
666 | case 'e': | ||
667 | case 'E': | ||
668 | if (!is_integer(optarg)) { | ||
669 | usage2(_("Retries interval must be a positive integer"), optarg); | ||
670 | } else { | ||
671 | config.snmp_params.snmp_session.retries = atoi(optarg); | ||
672 | } | ||
798 | break; | 673 | break; |
799 | case 't': /* timeout period */ | 674 | case 't': /* timeout period */ |
800 | if (!is_integer(optarg)) | 675 | if (!is_integer(optarg)) { |
801 | usage2(_("Timeout interval must be a positive integer"), optarg); | 676 | usage2(_("Timeout interval must be a positive integer"), optarg); |
802 | else | 677 | } else { |
803 | timeout_interval = atoi(optarg); | 678 | timeout_interval = (unsigned int)atoi(optarg); |
679 | } | ||
804 | break; | 680 | break; |
805 | 681 | ||
806 | /* Test parameters */ | 682 | /* Test parameters */ |
807 | case 'c': /* critical threshold */ | 683 | case 'c': /* critical threshold */ |
808 | critical_thresholds = optarg; | 684 | check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, true); |
809 | break; | 685 | break; |
810 | case 'w': /* warning threshold */ | 686 | case 'w': /* warning threshold */ |
811 | warning_thresholds = optarg; | 687 | check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, false); |
812 | break; | ||
813 | case 'e': /* PRELIMINARY - may change */ | ||
814 | case 'E': /* PRELIMINARY - may change */ | ||
815 | if (!is_integer(optarg)) | ||
816 | usage2(_("Retries interval must be a positive integer"), optarg); | ||
817 | else | ||
818 | retries = atoi(optarg); | ||
819 | break; | 688 | break; |
820 | case 'o': /* object identifier */ | 689 | case 'o': /* object identifier */ |
821 | if (strspn(optarg, "0123456789.,") != strlen(optarg)) { | 690 | if (strspn(optarg, "0123456789.,") != strlen(optarg)) { |
@@ -824,306 +693,292 @@ int process_arguments(int argc, char **argv) { | |||
824 | * so we have a mib variable, rather than just an SNMP OID, | 693 | * so we have a mib variable, rather than just an SNMP OID, |
825 | * so we have to actually read the mib files | 694 | * so we have to actually read the mib files |
826 | */ | 695 | */ |
827 | needmibs = true; | 696 | config.snmp_params.need_mibs = true; |
828 | } | ||
829 | for (char *ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) { | ||
830 | while (j >= oids_size) { | ||
831 | oids_size += OID_COUNT_STEP; | ||
832 | oids = realloc(oids, oids_size * sizeof(*oids)); | ||
833 | } | ||
834 | oids[j] = strdup(ptr); | ||
835 | } | 697 | } |
836 | numoids = j; | 698 | |
837 | if (option_char == 'E' || option_char == 'e') { | 699 | for (char *ptr = strtok(optarg, ", "); ptr != NULL; |
838 | jj++; | 700 | ptr = strtok(NULL, ", "), tmp_oid_counter++) { |
839 | while (j + 1 >= eval_size) { | 701 | config.snmp_params.test_units[tmp_oid_counter].oid = strdup(ptr); |
840 | eval_size += OID_COUNT_STEP; | ||
841 | eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); | ||
842 | memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); | ||
843 | } | ||
844 | if (option_char == 'E') | ||
845 | eval_method[j + 1] |= WARN_PRESENT; | ||
846 | else if (option_char == 'e') | ||
847 | eval_method[j + 1] |= CRIT_PRESENT; | ||
848 | } | 702 | } |
849 | break; | 703 | break; |
850 | case 'z': /* Null OID Return Check */ | 704 | case 'z': /* Null OID Return Check */ |
851 | if (!is_integer(optarg)) | 705 | if (!is_integer(optarg)) { |
852 | usage2(_("Exit status must be a positive integer"), optarg); | 706 | usage2(_("Exit status must be a positive integer"), optarg); |
853 | else | 707 | } else { |
854 | nulloid = atoi(optarg); | 708 | config.evaluation_params.nulloid_result = atoi(optarg); |
709 | } | ||
855 | break; | 710 | break; |
856 | case 's': /* string or substring */ | 711 | case 's': /* string or substring */ |
857 | strncpy(string_value, optarg, sizeof(string_value) - 1); | 712 | strncpy(config.evaluation_params.string_cmp_value, optarg, |
858 | string_value[sizeof(string_value) - 1] = 0; | 713 | sizeof(config.evaluation_params.string_cmp_value) - 1); |
859 | while (jj >= eval_size) { | 714 | config.evaluation_params |
860 | eval_size += OID_COUNT_STEP; | 715 | .string_cmp_value[sizeof(config.evaluation_params.string_cmp_value) - 1] = 0; |
861 | eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); | 716 | config.snmp_params.test_units[eval_counter++].eval_mthd.crit_string = true; |
862 | memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); | ||
863 | } | ||
864 | eval_method[jj++] = CRIT_STRING; | ||
865 | break; | 717 | break; |
866 | case 'R': /* regex */ | 718 | case 'R': /* regex */ |
867 | cflags = REG_ICASE; | 719 | cflags = REG_ICASE; |
868 | // fall through | 720 | // fall through |
869 | case 'r': /* regex */ | 721 | case 'r': /* regex */ |
722 | { | ||
723 | char regex_expect[MAX_INPUT_BUFFER] = ""; | ||
870 | cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; | 724 | cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; |
871 | strncpy(regex_expect, optarg, sizeof(regex_expect) - 1); | 725 | strncpy(regex_expect, optarg, sizeof(regex_expect) - 1); |
872 | regex_expect[sizeof(regex_expect) - 1] = 0; | 726 | regex_expect[sizeof(regex_expect) - 1] = 0; |
873 | errcode = regcomp(&preg, regex_expect, cflags); | 727 | int errcode = regcomp(&config.evaluation_params.regex_cmp_value, regex_expect, cflags); |
874 | if (errcode != 0) { | 728 | if (errcode != 0) { |
875 | regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); | 729 | char errbuf[MAX_INPUT_BUFFER] = ""; |
876 | printf(_("Could Not Compile Regular Expression")); | 730 | regerror(errcode, &config.evaluation_params.regex_cmp_value, errbuf, |
877 | return ERROR; | 731 | MAX_INPUT_BUFFER); |
878 | } | 732 | printf("Could Not Compile Regular Expression: %s", errbuf); |
879 | while (jj >= eval_size) { | 733 | process_arguments_wrapper result = { |
880 | eval_size += OID_COUNT_STEP; | 734 | .errorcode = ERROR, |
881 | eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); | 735 | }; |
882 | memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); | 736 | return result; |
883 | } | 737 | } |
884 | eval_method[jj++] = CRIT_REGEX; | 738 | config.snmp_params.test_units[eval_counter++].eval_mthd.crit_regex = true; |
885 | break; | 739 | } break; |
886 | |||
887 | /* Format */ | ||
888 | case 'd': /* delimiter */ | ||
889 | delimiter = strscpy(delimiter, optarg); | ||
890 | break; | ||
891 | case 'D': /* output-delimiter */ | ||
892 | output_delim = strscpy(output_delim, optarg); | ||
893 | break; | ||
894 | case 'l': /* label */ | 740 | case 'l': /* label */ |
895 | nlabels++; | 741 | { |
896 | if (nlabels > labels_size) { | 742 | if (labels_counter >= config.snmp_params.num_of_test_units) { |
897 | labels_size += 8; | 743 | break; |
898 | labels = realloc(labels, labels_size * sizeof(*labels)); | 744 | } |
899 | if (labels == NULL) | 745 | char *ptr = trim_whitespaces_and_check_quoting(optarg); |
900 | die(STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels); | 746 | if (ptr[0] == '\'') { |
747 | config.snmp_params.test_units[labels_counter].label = ptr + 1; | ||
748 | } else { | ||
749 | config.snmp_params.test_units[labels_counter].label = ptr; | ||
901 | } | 750 | } |
902 | labels[nlabels - 1] = optarg; | 751 | |
903 | char *ptr = thisarg(optarg); | 752 | while (ptr && (ptr = get_next_argument(ptr))) { |
904 | labels[nlabels - 1] = ptr; | 753 | labels_counter++; |
905 | if (ptr[0] == '\'') | 754 | ptr = trim_whitespaces_and_check_quoting(ptr); |
906 | labels[nlabels - 1] = ptr + 1; | 755 | if (ptr[0] == '\'') { |
907 | while (ptr && (ptr = nextarg(ptr))) { | 756 | config.snmp_params.test_units[labels_counter].label = ptr + 1; |
908 | nlabels++; | 757 | } else { |
909 | if (nlabels > labels_size) { | 758 | config.snmp_params.test_units[labels_counter].label = ptr; |
910 | labels_size += 8; | ||
911 | labels = realloc(labels, labels_size * sizeof(*labels)); | ||
912 | if (labels == NULL) | ||
913 | die(STATE_UNKNOWN, _("Could not reallocate labels\n")); | ||
914 | } | 759 | } |
915 | ptr = thisarg(ptr); | ||
916 | if (ptr[0] == '\'') | ||
917 | labels[nlabels - 1] = ptr + 1; | ||
918 | else | ||
919 | labels[nlabels - 1] = ptr; | ||
920 | } | 760 | } |
921 | break; | 761 | labels_counter++; |
762 | } break; | ||
922 | case 'u': /* units */ | 763 | case 'u': /* units */ |
923 | units = optarg; | 764 | { |
924 | nunits++; | 765 | if (unitv_counter >= config.snmp_params.num_of_test_units) { |
925 | if (nunits > unitv_size) { | 766 | break; |
926 | unitv_size += 8; | ||
927 | unitv = realloc(unitv, unitv_size * sizeof(*unitv)); | ||
928 | if (unitv == NULL) | ||
929 | die(STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits); | ||
930 | } | 767 | } |
931 | unitv[nunits - 1] = optarg; | 768 | char *ptr = trim_whitespaces_and_check_quoting(optarg); |
932 | ptr = thisarg(optarg); | 769 | if (ptr[0] == '\'') { |
933 | unitv[nunits - 1] = ptr; | 770 | config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1; |
934 | if (ptr[0] == '\'') | 771 | } else { |
935 | unitv[nunits - 1] = ptr + 1; | 772 | config.snmp_params.test_units[unitv_counter].unit_value = ptr; |
936 | while (ptr && (ptr = nextarg(ptr))) { | 773 | } |
937 | if (nunits > unitv_size) { | 774 | while (ptr && (ptr = get_next_argument(ptr))) { |
938 | unitv_size += 8; | 775 | unitv_counter++; |
939 | unitv = realloc(unitv, unitv_size * sizeof(*unitv)); | 776 | ptr = trim_whitespaces_and_check_quoting(ptr); |
940 | if (units == NULL) | 777 | if (ptr[0] == '\'') { |
941 | die(STATE_UNKNOWN, _("Could not realloc() units\n")); | 778 | config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1; |
779 | } else { | ||
780 | config.snmp_params.test_units[unitv_counter].unit_value = ptr; | ||
942 | } | 781 | } |
943 | nunits++; | ||
944 | ptr = thisarg(ptr); | ||
945 | if (ptr[0] == '\'') | ||
946 | unitv[nunits - 1] = ptr + 1; | ||
947 | else | ||
948 | unitv[nunits - 1] = ptr; | ||
949 | } | 782 | } |
783 | unitv_counter++; | ||
784 | } break; | ||
785 | case offset_index: | ||
786 | config.evaluation_params.offset = strtod(optarg, NULL); | ||
787 | config.evaluation_params.offset_set = true; | ||
950 | break; | 788 | break; |
951 | case L_CALCULATE_RATE: | 789 | case invert_search_index: |
952 | if (calculate_rate == 0) | 790 | config.evaluation_params.invert_search = false; |
953 | np_enable_state(NULL, 1); | ||
954 | calculate_rate = 1; | ||
955 | break; | ||
956 | case L_RATE_MULTIPLIER: | ||
957 | if (!is_integer(optarg) || ((rate_multiplier = atoi(optarg)) <= 0)) | ||
958 | usage2(_("Rate multiplier must be a positive integer"), optarg); | ||
959 | break; | ||
960 | case L_OFFSET: | ||
961 | offset = strtod(optarg, NULL); | ||
962 | break; | ||
963 | case L_INVERT_SEARCH: | ||
964 | invert_search = 1; | ||
965 | break; | 791 | break; |
966 | case 'O': | 792 | case 'O': |
967 | perf_labels = 0; | 793 | config.evaluation_params.use_oid_as_perf_data_label = true; |
968 | break; | 794 | break; |
969 | case '4': | 795 | case '4': |
796 | // The default, do something here to be exclusive to -6 instead of doing nothing? | ||
797 | connection_prefix = "udp"; | ||
970 | break; | 798 | break; |
971 | case '6': | 799 | case '6': |
972 | xasprintf(&ip_version, "udp6:"); | 800 | connection_prefix = "udp6"; |
973 | if (verbose > 2) | 801 | break; |
974 | printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); | 802 | case connection_prefix_index: |
803 | connection_prefix = optarg; | ||
975 | break; | 804 | break; |
976 | case 'M': | 805 | case 'M': |
977 | if (strspn(optarg, "0123456789.,") == strlen(optarg)) { | 806 | if (strspn(optarg, "0123456789.,") == strlen(optarg)) { |
978 | multiplier = strtod(optarg, NULL); | 807 | config.evaluation_params.multiplier = strtod(optarg, NULL); |
808 | config.evaluation_params.multiplier_set = true; | ||
979 | } | 809 | } |
980 | break; | 810 | break; |
981 | case 'f': | 811 | case ignore_mib_parsing_errors_index: |
982 | if (multiplier != 1.0) { | 812 | config.snmp_params.ignore_mib_parsing_errors = true; |
983 | fmtstr = optarg; | 813 | break; |
984 | fmtstr_set = true; | 814 | case 'f': // Deprecated format option for floating point values |
815 | break; | ||
816 | case output_format_index: { | ||
817 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
818 | if (!parser.parsing_success) { | ||
819 | // TODO List all available formats here, maybe add anothoer usage function | ||
820 | printf("Invalid output format: %s\n", optarg); | ||
821 | exit(STATE_UNKNOWN); | ||
822 | } | ||
823 | |||
824 | config.output_format_is_set = true; | ||
825 | config.output_format = parser.output_format; | ||
826 | break; | ||
827 | } | ||
828 | case calculate_rate: | ||
829 | config.evaluation_params.calculate_rate = true; | ||
830 | break; | ||
831 | case rate_multiplier: | ||
832 | if (!is_integer(optarg) || | ||
833 | ((config.evaluation_params.rate_multiplier = (unsigned int)atoi(optarg)) <= 0)) { | ||
834 | usage2(_("Rate multiplier must be a positive integer"), optarg); | ||
985 | } | 835 | } |
986 | break; | 836 | break; |
987 | case L_IGNORE_MIB_PARSING_ERRORS: | 837 | default: |
988 | ignore_mib_parsing_errors = true; | 838 | die(STATE_UNKNOWN, "Unknown option"); |
989 | } | 839 | } |
990 | } | 840 | } |
991 | 841 | ||
992 | if (server_address == NULL) | 842 | if (config.snmp_params.snmp_session.peername == NULL) { |
993 | server_address = argv[optind]; | 843 | config.snmp_params.snmp_session.peername = argv[optind]; |
994 | 844 | } | |
995 | if (community == NULL) | ||
996 | community = strdup(DEFAULT_COMMUNITY); | ||
997 | |||
998 | return validate_arguments(); | ||
999 | } | ||
1000 | |||
1001 | /****************************************************************************** | ||
1002 | |||
1003 | @@- | ||
1004 | <sect3> | ||
1005 | <title>validate_arguments</title> | ||
1006 | |||
1007 | <para>&PROTO_validate_arguments;</para> | ||
1008 | |||
1009 | <para>Checks to see if the default miblist needs to be loaded. Also verifies | ||
1010 | the authentication and authorization combinations based on protocol version | ||
1011 | selected.</para> | ||
1012 | |||
1013 | <para></para> | ||
1014 | |||
1015 | </sect3> | ||
1016 | -@@ | ||
1017 | ******************************************************************************/ | ||
1018 | 845 | ||
1019 | static int validate_arguments() { | 846 | // Build true peername here if necessary |
1020 | /* check whether to load locally installed MIBS (CPU/disk intensive) */ | 847 | if (connection_prefix != NULL) { |
1021 | if (miblist == NULL) { | 848 | // We got something in the connection prefix |
1022 | if (needmibs) { | 849 | if (strcasecmp(connection_prefix, "udp") == 0) { |
1023 | miblist = strdup(DEFAULT_MIBLIST); | 850 | // The default, do nothing |
851 | } else if (strcasecmp(connection_prefix, "tcp") == 0) { | ||
852 | // use tcp/ipv4 | ||
853 | xasprintf(&config.snmp_params.snmp_session.peername, "tcp:%s", | ||
854 | config.snmp_params.snmp_session.peername); | ||
855 | } else if (strcasecmp(connection_prefix, "tcp6") == 0 || | ||
856 | strcasecmp(connection_prefix, "tcpv6") == 0 || | ||
857 | strcasecmp(connection_prefix, "tcpipv6") == 0 || | ||
858 | strcasecmp(connection_prefix, "udp6") == 0 || | ||
859 | strcasecmp(connection_prefix, "udpipv6") == 0 || | ||
860 | strcasecmp(connection_prefix, "udpv6") == 0) { | ||
861 | // Man page (or net-snmp) code says IPv6 addresses should be wrapped in [], but it | ||
862 | // works anyway therefore do nothing here | ||
863 | xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s", connection_prefix, | ||
864 | config.snmp_params.snmp_session.peername); | ||
865 | } else if (strcmp(connection_prefix, "tls") == 0) { | ||
866 | // TODO: Anything else to do here? | ||
867 | xasprintf(&config.snmp_params.snmp_session.peername, "tls:%s", | ||
868 | config.snmp_params.snmp_session.peername); | ||
869 | } else if (strcmp(connection_prefix, "dtls") == 0) { | ||
870 | // TODO: Anything else to do here? | ||
871 | xasprintf(&config.snmp_params.snmp_session.peername, "dtls:%s", | ||
872 | config.snmp_params.snmp_session.peername); | ||
873 | } else if (strcmp(connection_prefix, "unix") == 0) { | ||
874 | // TODO: Check whether this is a valid path? | ||
875 | xasprintf(&config.snmp_params.snmp_session.peername, "unix:%s", | ||
876 | config.snmp_params.snmp_session.peername); | ||
877 | } else if (strcmp(connection_prefix, "ipx") == 0) { | ||
878 | xasprintf(&config.snmp_params.snmp_session.peername, "ipx:%s", | ||
879 | config.snmp_params.snmp_session.peername); | ||
1024 | } else { | 880 | } else { |
1025 | miblist = ""; /* don't read any mib files for numeric oids */ | 881 | // Don't know that prefix, die here |
882 | die(STATE_UNKNOWN, "Unknown connection prefix"); | ||
1026 | } | 883 | } |
1027 | } | 884 | } |
1028 | 885 | ||
1029 | /* Check server_address is given */ | 886 | /* Check server_address is given */ |
1030 | if (server_address == NULL) | 887 | if (config.snmp_params.snmp_session.peername == NULL) { |
1031 | die(STATE_UNKNOWN, _("No host specified\n")); | 888 | die(STATE_UNKNOWN, _("No host specified\n")); |
889 | } | ||
1032 | 890 | ||
1033 | /* Check oid is given */ | 891 | if (port != NULL) { |
1034 | if (numoids == 0) | 892 | xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s", |
1035 | die(STATE_UNKNOWN, _("No OIDs specified\n")); | 893 | config.snmp_params.snmp_session.peername, port); |
894 | } | ||
1036 | 895 | ||
1037 | if (proto == NULL) | 896 | /* check whether to load locally installed MIBS (CPU/disk intensive) */ |
1038 | xasprintf(&proto, DEFAULT_PROTOCOL); | 897 | if (miblist == NULL) { |
1039 | 898 | if (config.snmp_params.need_mibs) { | |
1040 | if ((strcmp(proto, "1") == 0) || (strcmp(proto, "2c") == 0)) { /* snmpv1 or snmpv2c */ | 899 | setenv("MIBLS", DEFAULT_MIBLIST, 1); |
1041 | numauthpriv = 2; | 900 | } else { |
1042 | authpriv = calloc(numauthpriv, sizeof(char *)); | 901 | setenv("MIBLS", "NONE", 1); |
1043 | authpriv[0] = strdup("-c"); | 902 | miblist = ""; /* don't read any mib files for numeric oids */ |
1044 | authpriv[1] = strdup(community); | ||
1045 | } else if (strcmp(proto, "3") == 0) { /* snmpv3 args */ | ||
1046 | if (!(context == NULL)) { | ||
1047 | numcontext = 2; | ||
1048 | contextargs = calloc(numcontext, sizeof(char *)); | ||
1049 | contextargs[0] = strdup("-n"); | ||
1050 | contextargs[1] = strdup(context); | ||
1051 | } | 903 | } |
904 | } else { | ||
905 | // Blatantly stolen from snmplib/snmp_parse_args | ||
906 | setenv("MIBS", miblist, 1); | ||
907 | } | ||
1052 | 908 | ||
1053 | if (seclevel == NULL) | 909 | // Historical default is SNMP v2c |
1054 | xasprintf(&seclevel, "noAuthNoPriv"); | 910 | if (!snmp_version_set_explicitely && config.snmp_params.snmp_session.community != NULL) { |
911 | config.snmp_params.snmp_session.version = SNMP_VERSION_2c; | ||
912 | } | ||
1055 | 913 | ||
1056 | if (secname == NULL) | 914 | if ((config.snmp_params.snmp_session.version == SNMP_VERSION_1) || |
915 | (config.snmp_params.snmp_session.version == SNMP_VERSION_2c)) { /* snmpv1 or snmpv2c */ | ||
916 | /* | ||
917 | config.numauthpriv = 2; | ||
918 | config.authpriv = calloc(config.numauthpriv, sizeof(char *)); | ||
919 | config.authpriv[0] = strdup("-c"); | ||
920 | config.authpriv[1] = strdup(community); | ||
921 | */ | ||
922 | } else if (config.snmp_params.snmp_session.version == SNMP_VERSION_3) { /* snmpv3 args */ | ||
923 | // generate keys for priv and auth here (if demanded) | ||
924 | |||
925 | if (config.snmp_params.snmp_session.securityName == NULL) { | ||
1057 | die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname"); | 926 | die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname"); |
927 | } | ||
1058 | 928 | ||
1059 | if (strcmp(seclevel, "noAuthNoPriv") == 0) { | 929 | switch (config.snmp_params.snmp_session.securityLevel) { |
1060 | numauthpriv = 4; | 930 | case SNMP_SEC_LEVEL_AUTHPRIV: { |
1061 | authpriv = calloc(numauthpriv, sizeof(char *)); | 931 | if (authpasswd == NULL) { |
1062 | authpriv[0] = strdup("-l"); | 932 | die(STATE_UNKNOWN, |
1063 | authpriv[1] = strdup("noAuthNoPriv"); | 933 | "No authentication passphrase was given, but authorization was requested"); |
1064 | authpriv[2] = strdup("-u"); | ||
1065 | authpriv[3] = strdup(secname); | ||
1066 | } else { | ||
1067 | if (!((strcmp(seclevel, "authNoPriv") == 0) || (strcmp(seclevel, "authPriv") == 0))) { | ||
1068 | usage2(_("Invalid seclevel"), seclevel); | ||
1069 | } | 934 | } |
1070 | 935 | // auth and priv | |
1071 | if (authproto == NULL) | 936 | int priv_key_generated = generate_Ku( |
1072 | xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); | 937 | config.snmp_params.snmp_session.securityPrivProto, |
1073 | 938 | (unsigned int)config.snmp_params.snmp_session.securityPrivProtoLen, authpasswd, | |
1074 | if (authpasswd == NULL) | 939 | strlen((const char *)authpasswd), config.snmp_params.snmp_session.securityPrivKey, |
1075 | die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); | 940 | &config.snmp_params.snmp_session.securityPrivKeyLen); |
1076 | 941 | ||
1077 | if (strcmp(seclevel, "authNoPriv") == 0) { | 942 | if (priv_key_generated != SNMPERR_SUCCESS) { |
1078 | numauthpriv = 8; | 943 | die(STATE_UNKNOWN, "Failed to generate privacy key"); |
1079 | authpriv = calloc(numauthpriv, sizeof(char *)); | ||
1080 | authpriv[0] = strdup("-l"); | ||
1081 | authpriv[1] = strdup("authNoPriv"); | ||
1082 | authpriv[2] = strdup("-a"); | ||
1083 | authpriv[3] = strdup(authproto); | ||
1084 | authpriv[4] = strdup("-u"); | ||
1085 | authpriv[5] = strdup(secname); | ||
1086 | authpriv[6] = strdup("-A"); | ||
1087 | authpriv[7] = strdup(authpasswd); | ||
1088 | } else if (strcmp(seclevel, "authPriv") == 0) { | ||
1089 | if (privproto == NULL) | ||
1090 | xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL); | ||
1091 | |||
1092 | if (privpasswd == NULL) | ||
1093 | die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd"); | ||
1094 | |||
1095 | numauthpriv = 12; | ||
1096 | authpriv = calloc(numauthpriv, sizeof(char *)); | ||
1097 | authpriv[0] = strdup("-l"); | ||
1098 | authpriv[1] = strdup("authPriv"); | ||
1099 | authpriv[2] = strdup("-a"); | ||
1100 | authpriv[3] = strdup(authproto); | ||
1101 | authpriv[4] = strdup("-u"); | ||
1102 | authpriv[5] = strdup(secname); | ||
1103 | authpriv[6] = strdup("-A"); | ||
1104 | authpriv[7] = strdup(authpasswd); | ||
1105 | authpriv[8] = strdup("-x"); | ||
1106 | authpriv[9] = strdup(privproto); | ||
1107 | authpriv[10] = strdup("-X"); | ||
1108 | authpriv[11] = strdup(privpasswd); | ||
1109 | } | 944 | } |
1110 | } | 945 | } |
1111 | 946 | // fall through | |
1112 | } else { | 947 | case SNMP_SEC_LEVEL_AUTHNOPRIV: { |
1113 | usage2(_("Invalid SNMP version"), proto); | 948 | if (privpasswd == NULL) { |
949 | die(STATE_UNKNOWN, "No privacy passphrase was given, but privacy was requested"); | ||
950 | } | ||
951 | int auth_key_generated = generate_Ku( | ||
952 | config.snmp_params.snmp_session.securityAuthProto, | ||
953 | (unsigned int)config.snmp_params.snmp_session.securityAuthProtoLen, privpasswd, | ||
954 | strlen((const char *)privpasswd), config.snmp_params.snmp_session.securityAuthKey, | ||
955 | &config.snmp_params.snmp_session.securityAuthKeyLen); | ||
956 | |||
957 | if (auth_key_generated != SNMPERR_SUCCESS) { | ||
958 | die(STATE_UNKNOWN, "Failed to generate privacy key"); | ||
959 | } | ||
960 | } break; | ||
961 | case SNMP_SEC_LEVEL_NOAUTH: | ||
962 | // No auth, no priv, not much todo | ||
963 | break; | ||
964 | } | ||
1114 | } | 965 | } |
1115 | 966 | ||
1116 | return OK; | 967 | process_arguments_wrapper result = { |
968 | .config = config, | ||
969 | .errorcode = OK, | ||
970 | }; | ||
971 | return result; | ||
1117 | } | 972 | } |
1118 | 973 | ||
1119 | /* trim leading whitespace | 974 | /* trim leading whitespace |
1120 | if there is a leading quote, make sure it balances */ | 975 | if there is a leading quote, make sure it balances */ |
1121 | 976 | char *trim_whitespaces_and_check_quoting(char *str) { | |
1122 | static char *thisarg(char *str) { | ||
1123 | str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ | 977 | str += strspn(str, " \t\r\n"); /* trim any leading whitespace */ |
1124 | if (str[0] == '\'') { /* handle SIMPLE quoted strings */ | 978 | if (str[0] == '\'') { /* handle SIMPLE quoted strings */ |
1125 | if (strlen(str) == 1 || !strstr(str + 1, "'")) | 979 | if (strlen(str) == 1 || !strstr(str + 1, "'")) { |
1126 | die(STATE_UNKNOWN, _("Unbalanced quotes\n")); | 980 | die(STATE_UNKNOWN, _("Unbalanced quotes\n")); |
981 | } | ||
1127 | } | 982 | } |
1128 | return str; | 983 | return str; |
1129 | } | 984 | } |
@@ -1132,23 +987,21 @@ static char *thisarg(char *str) { | |||
1132 | set the trailing quote to '\x0' | 987 | set the trailing quote to '\x0' |
1133 | if the string continues, advance beyond the comma */ | 988 | if the string continues, advance beyond the comma */ |
1134 | 989 | ||
1135 | static char *nextarg(char *str) { | 990 | char *get_next_argument(char *str) { |
1136 | if (str[0] == '\'') { | 991 | if (str[0] == '\'') { |
1137 | str[0] = 0; | 992 | str[0] = 0; |
1138 | if (strlen(str) > 1) { | 993 | if (strlen(str) > 1) { |
1139 | str = strstr(str + 1, "'"); | 994 | str = strstr(str + 1, "'"); |
1140 | return (++str); | 995 | return (++str); |
1141 | } else { | ||
1142 | return NULL; | ||
1143 | } | 996 | } |
997 | return NULL; | ||
1144 | } | 998 | } |
1145 | if (str[0] == ',') { | 999 | if (str[0] == ',') { |
1146 | str[0] = 0; | 1000 | str[0] = 0; |
1147 | if (strlen(str) > 1) { | 1001 | if (strlen(str) > 1) { |
1148 | return (++str); | 1002 | return (++str); |
1149 | } else { | ||
1150 | return NULL; | ||
1151 | } | 1003 | } |
1004 | return NULL; | ||
1152 | } | 1005 | } |
1153 | if ((str = strstr(str, ",")) && strlen(str) > 1) { | 1006 | if ((str = strstr(str, ",")) && strlen(str) > 1) { |
1154 | str[0] = 0; | 1007 | str[0] = 0; |
@@ -1157,41 +1010,7 @@ static char *nextarg(char *str) { | |||
1157 | return NULL; | 1010 | return NULL; |
1158 | } | 1011 | } |
1159 | 1012 | ||
1160 | /* multiply result (values 0 < n < 1 work as divider) */ | 1013 | void print_help(void) { |
1161 | static char *multiply(char *str) { | ||
1162 | if (multiplier == 1) | ||
1163 | return (str); | ||
1164 | |||
1165 | if (verbose > 2) | ||
1166 | printf(" multiply input: %s\n", str); | ||
1167 | |||
1168 | char *endptr; | ||
1169 | double val = strtod(str, &endptr); | ||
1170 | if ((val == 0.0) && (endptr == str)) { | ||
1171 | die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str); | ||
1172 | } | ||
1173 | |||
1174 | if (verbose > 2) | ||
1175 | printf(" multiply extracted double: %f\n", val); | ||
1176 | |||
1177 | val *= multiplier; | ||
1178 | char *conv = "%f"; | ||
1179 | if (fmtstr_set) { | ||
1180 | conv = fmtstr; | ||
1181 | } | ||
1182 | if (val == (int)val) { | ||
1183 | snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val); | ||
1184 | } else { | ||
1185 | if (verbose > 2) | ||
1186 | printf(" multiply using format: %s\n", conv); | ||
1187 | snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val); | ||
1188 | } | ||
1189 | if (verbose > 2) | ||
1190 | printf(" multiply result: %s\n", buffer); | ||
1191 | return buffer; | ||
1192 | } | ||
1193 | |||
1194 | static void print_help(void) { | ||
1195 | print_revision(progname, NP_VERSION); | 1014 | print_revision(progname, NP_VERSION); |
1196 | 1015 | ||
1197 | printf(COPYRIGHT, copyright, email); | 1016 | printf(COPYRIGHT, copyright, email); |
@@ -1204,8 +1023,6 @@ static void print_help(void) { | |||
1204 | 1023 | ||
1205 | printf(UT_HELP_VRSN); | 1024 | printf(UT_HELP_VRSN); |
1206 | printf(UT_EXTRA_OPTS); | 1025 | printf(UT_EXTRA_OPTS); |
1207 | printf(UT_IPv46); | ||
1208 | |||
1209 | printf(UT_HOST_PORT, 'p', DEFAULT_PORT); | 1026 | printf(UT_HOST_PORT, 'p', DEFAULT_PORT); |
1210 | 1027 | ||
1211 | /* SNMP and Authentication Protocol */ | 1028 | /* SNMP and Authentication Protocol */ |
@@ -1217,13 +1034,15 @@ static void print_help(void) { | |||
1217 | printf(" %s\n", _("SNMPv3 context")); | 1034 | printf(" %s\n", _("SNMPv3 context")); |
1218 | printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); | 1035 | printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); |
1219 | printf(" %s\n", _("SNMPv3 securityLevel")); | 1036 | printf(" %s\n", _("SNMPv3 securityLevel")); |
1220 | printf(" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); | 1037 | printf(" %s\n", "-a, --authproto=[MD5|SHA]"); |
1221 | printf(" %s\n", | 1038 | printf(" %s\n", _("SNMPv3 auth proto")); |
1222 | _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); | 1039 | #ifdef HAVE_USM_DES_PRIV_PROTOCOL |
1223 | printf(" %s\n", _("if < 5.8 SHA (1) and MD5 should be available, if >= 5.8 additionally SHA-224, SHA-256, SHA-384 and SHA-512")); | 1040 | printf(" %s\n", "-x, --privproto=[DES|AES]"); |
1224 | printf(" %s\n", "-x, --privproto=PRIVACY_PROTOCOL"); | 1041 | printf(" %s\n", _("SNMPv3 priv proto (default DES)")); |
1225 | printf(" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); | 1042 | #else |
1226 | printf(" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); | 1043 | printf(" %s\n", "-x, --privproto=[AES]"); |
1044 | printf(" %s\n", _("SNMPv3 priv proto (default AES)")); | ||
1045 | #endif | ||
1227 | 1046 | ||
1228 | /* Authentication Tokens*/ | 1047 | /* Authentication Tokens*/ |
1229 | printf(" %s\n", "-C, --community=STRING"); | 1048 | printf(" %s\n", "-C, --community=STRING"); |
@@ -1235,15 +1054,18 @@ static void print_help(void) { | |||
1235 | printf(" %s\n", _("SNMPv3 authentication password")); | 1054 | printf(" %s\n", _("SNMPv3 authentication password")); |
1236 | printf(" %s\n", "-X, --privpasswd=PASSWORD"); | 1055 | printf(" %s\n", "-X, --privpasswd=PASSWORD"); |
1237 | printf(" %s\n", _("SNMPv3 privacy password")); | 1056 | printf(" %s\n", _("SNMPv3 privacy password")); |
1057 | printf(" %s\n", "--connection-prefix"); | ||
1058 | printf(" Connection prefix, may be one of udp, udp6, tcp, unix, ipx, udp6, udpv6, udpipv6, " | ||
1059 | "tcp6, tcpv6, tcpipv6, tls, dtls - " | ||
1060 | "default is \"udp\"\n"); | ||
1238 | 1061 | ||
1239 | /* OID Stuff */ | 1062 | /* OID Stuff */ |
1240 | printf(" %s\n", "-o, --oid=OID(s)"); | 1063 | printf(" %s\n", "-o, --oid=OID(s)"); |
1241 | printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); | 1064 | printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); |
1242 | printf(" %s\n", "-m, --miblist=STRING"); | 1065 | printf(" %s\n", "-m, --miblist=STRING"); |
1243 | printf(" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); | 1066 | printf(" %s\n", |
1067 | _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); | ||
1244 | printf(" %s\n", _("for symbolic OIDs.)")); | 1068 | printf(" %s\n", _("for symbolic OIDs.)")); |
1245 | printf(" %s\n", "-d, --delimiter=STRING"); | ||
1246 | printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); | ||
1247 | printf(" %s\n", _("Any data on the right hand side of the delimiter is considered")); | 1069 | printf(" %s\n", _("Any data on the right hand side of the delimiter is considered")); |
1248 | printf(" %s\n", _("to be the data that should be used in the evaluation.")); | 1070 | printf(" %s\n", _("to be the data that should be used in the evaluation.")); |
1249 | printf(" %s\n", "-z, --nulloid=#"); | 1071 | printf(" %s\n", "-z, --nulloid=#"); |
@@ -1260,10 +1082,6 @@ static void print_help(void) { | |||
1260 | printf(" %s\n", _("Warning threshold range(s)")); | 1082 | printf(" %s\n", _("Warning threshold range(s)")); |
1261 | printf(" %s\n", "-c, --critical=THRESHOLD(s)"); | 1083 | printf(" %s\n", "-c, --critical=THRESHOLD(s)"); |
1262 | printf(" %s\n", _("Critical threshold range(s)")); | 1084 | printf(" %s\n", _("Critical threshold range(s)")); |
1263 | printf(" %s\n", "--rate"); | ||
1264 | printf(" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); | ||
1265 | printf(" %s\n", "--rate-multiplier"); | ||
1266 | printf(" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute")); | ||
1267 | printf(" %s\n", "--offset=OFFSET"); | 1085 | printf(" %s\n", "--offset=OFFSET"); |
1268 | printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data")); | 1086 | printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data")); |
1269 | 1087 | ||
@@ -1271,9 +1089,11 @@ static void print_help(void) { | |||
1271 | printf(" %s\n", "-s, --string=STRING"); | 1089 | printf(" %s\n", "-s, --string=STRING"); |
1272 | printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); | 1090 | printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); |
1273 | printf(" %s\n", "-r, --ereg=REGEX"); | 1091 | printf(" %s\n", "-r, --ereg=REGEX"); |
1274 | printf(" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); | 1092 | printf(" %s\n", |
1093 | _("Return OK state (for that OID) if extended regular expression REGEX matches")); | ||
1275 | printf(" %s\n", "-R, --eregi=REGEX"); | 1094 | printf(" %s\n", "-R, --eregi=REGEX"); |
1276 | printf(" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); | 1095 | printf(" %s\n", |
1096 | _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); | ||
1277 | printf(" %s\n", "--invert-search"); | 1097 | printf(" %s\n", "--invert-search"); |
1278 | printf(" %s\n", _("Invert search result (CRITICAL if found)")); | 1098 | printf(" %s\n", _("Invert search result (CRITICAL if found)")); |
1279 | 1099 | ||
@@ -1282,53 +1102,46 @@ static void print_help(void) { | |||
1282 | printf(" %s\n", _("Prefix label for output from plugin")); | 1102 | printf(" %s\n", _("Prefix label for output from plugin")); |
1283 | printf(" %s\n", "-u, --units=STRING"); | 1103 | printf(" %s\n", "-u, --units=STRING"); |
1284 | printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); | 1104 | printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); |
1285 | printf(" %s\n", "-D, --output-delimiter=STRING"); | ||
1286 | printf(" %s\n", _("Separates output on multiple OID requests")); | ||
1287 | printf(" %s\n", "-M, --multiplier=FLOAT"); | 1105 | printf(" %s\n", "-M, --multiplier=FLOAT"); |
1288 | printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1")); | 1106 | printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1")); |
1289 | printf(" %s\n", "-f, --fmtstr=STRING"); | 1107 | printf(UT_OUTPUT_FORMAT); |
1290 | printf(" %s\n", _("C-style format string for float values (see option -M)")); | ||
1291 | 1108 | ||
1292 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 1109 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
1293 | printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5")); | 1110 | printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: " |
1111 | "timeout_interval * retries + 5")); | ||
1294 | printf(" %s\n", "-e, --retries=INTEGER"); | 1112 | printf(" %s\n", "-e, --retries=INTEGER"); |
1295 | printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES); | 1113 | printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), |
1114 | DEFAULT_RETRIES); | ||
1296 | 1115 | ||
1297 | printf(" %s\n", "-O, --perf-oids"); | 1116 | printf(" %s\n", "-O, --perf-oids"); |
1298 | printf(" %s\n", _("Label performance data with OIDs instead of --label's")); | 1117 | printf(" %s\n", _("Label performance data with OIDs instead of --label's")); |
1299 | 1118 | ||
1300 | printf(" %s\n", "--ignore-mib-parsing-errors"); | 1119 | printf(" %s\n", "--ignore-mib-parsing-errors"); |
1301 | printf(" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files")); | 1120 | printf(" %s\n", _("Do to not print errors encountered when parsing MIB files")); |
1302 | 1121 | ||
1303 | printf(UT_VERBOSE); | 1122 | printf(UT_VERBOSE); |
1304 | 1123 | ||
1305 | printf("\n"); | 1124 | printf("\n"); |
1306 | printf("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package.")); | 1125 | printf("%s\n", _("This plugin relies (links against) on the NET-SNMP libraries.")); |
1307 | printf("%s\n", _("if you don't have the package installed, you will need to download it from")); | 1126 | printf("%s\n", |
1127 | _("if you don't have the libraries installed, you will need to download them from")); | ||
1308 | printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin.")); | 1128 | printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin.")); |
1309 | 1129 | ||
1310 | printf("\n"); | 1130 | printf("\n"); |
1311 | printf("%s\n", _("Notes:")); | 1131 | printf("%s\n", _("Notes:")); |
1312 | printf(" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); | 1132 | printf(" %s\n", |
1133 | _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); | ||
1313 | printf(" %s\n", _("list (lists with internal spaces must be quoted).")); | 1134 | printf(" %s\n", _("list (lists with internal spaces must be quoted).")); |
1314 | 1135 | ||
1315 | printf(" -%s", UT_THRESHOLDS_NOTES); | 1136 | printf(" -%s", UT_THRESHOLDS_NOTES); |
1316 | 1137 | ||
1317 | printf(" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); | 1138 | printf(" %s\n", |
1139 | _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); | ||
1318 | printf(" %s\n", _("- Note that only one string and one regex may be checked at present")); | 1140 | printf(" %s\n", _("- Note that only one string and one regex may be checked at present")); |
1319 | printf(" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); | 1141 | printf(" %s\n", |
1142 | _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); | ||
1320 | printf(" %s\n", _("returned from the SNMP query is an unsigned integer.")); | 1143 | printf(" %s\n", _("returned from the SNMP query is an unsigned integer.")); |
1321 | 1144 | ||
1322 | printf("\n"); | ||
1323 | printf("%s\n", _("Rate Calculation:")); | ||
1324 | printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when")); | ||
1325 | printf(" %s\n", _("calculating the counter difference since the last check. check_snmp")); | ||
1326 | printf(" %s\n", _("saves the last state information in a file so that the rate per second")); | ||
1327 | printf(" %s\n", _("can be calculated. Use the --rate option to save state information.")); | ||
1328 | printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK.")); | ||
1329 | printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so")); | ||
1330 | printf(" %s\n", _("changing the arguments will create a new state file.")); | ||
1331 | |||
1332 | printf(UT_SUPPORT); | 1145 | printf(UT_SUPPORT); |
1333 | } | 1146 | } |
1334 | 1147 | ||
@@ -1339,5 +1152,5 @@ void print_usage(void) { | |||
1339 | printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n"); | 1152 | printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n"); |
1340 | printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n"); | 1153 | printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n"); |
1341 | printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n"); | 1154 | printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n"); |
1342 | printf("[-M multiplier [-f format]]\n"); | 1155 | printf("[-M multiplier]\n"); |
1343 | } | 1156 | } |
diff --git a/plugins/check_snmp.d/check_snmp_helpers.c b/plugins/check_snmp.d/check_snmp_helpers.c new file mode 100644 index 00000000..ecbfc5dd --- /dev/null +++ b/plugins/check_snmp.d/check_snmp_helpers.c | |||
@@ -0,0 +1,934 @@ | |||
1 | #include "./check_snmp_helpers.h" | ||
2 | #include <string.h> | ||
3 | #include "../../lib/utils_base.h" | ||
4 | #include "config.h" | ||
5 | #include <assert.h> | ||
6 | #include "../utils.h" | ||
7 | #include "output.h" | ||
8 | #include "states.h" | ||
9 | #include <sys/stat.h> | ||
10 | #include <ctype.h> | ||
11 | |||
12 | extern int verbose; | ||
13 | |||
14 | check_snmp_test_unit check_snmp_test_unit_init() { | ||
15 | check_snmp_test_unit tmp = { | ||
16 | .threshold = mp_thresholds_init(), | ||
17 | }; | ||
18 | return tmp; | ||
19 | } | ||
20 | |||
21 | int check_snmp_set_thresholds(const char *threshold_string, check_snmp_test_unit test_units[], | ||
22 | size_t max_test_units, bool is_critical) { | ||
23 | |||
24 | if (threshold_string == NULL || strlen(threshold_string) == 0) { | ||
25 | // No input, do nothing | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | if (strchr(threshold_string, ',') != NULL) { | ||
30 | // Got a comma in the string, should be multiple values | ||
31 | size_t tu_index = 0; | ||
32 | |||
33 | while (threshold_string[0] == ',') { | ||
34 | // got commas at the beginning, so skip some values | ||
35 | tu_index++; | ||
36 | threshold_string++; | ||
37 | } | ||
38 | |||
39 | for (char *ptr = strtok(threshold_string, ", "); ptr != NULL; | ||
40 | ptr = strtok(NULL, ", "), tu_index++) { | ||
41 | |||
42 | if (tu_index > max_test_units) { | ||
43 | // More thresholds then values, just ignore them | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | // edge case: maybe we got `,,` to skip a value | ||
48 | if (strlen(ptr) == 0) { | ||
49 | // no threshold given, do not set it then | ||
50 | continue; | ||
51 | } | ||
52 | |||
53 | mp_range_parsed tmp = mp_parse_range_string(ptr); | ||
54 | if (tmp.error != MP_PARSING_SUCCES) { | ||
55 | die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", ptr); | ||
56 | } | ||
57 | |||
58 | if (is_critical) { | ||
59 | test_units[tu_index].threshold.critical = tmp.range; | ||
60 | test_units[tu_index].threshold.critical_is_set = true; | ||
61 | } else { | ||
62 | test_units[tu_index].threshold.warning = tmp.range; | ||
63 | test_units[tu_index].threshold.warning_is_set = true; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | } else { | ||
68 | // Single value | ||
69 | // only valid for the first test unit | ||
70 | mp_range_parsed tmp = mp_parse_range_string(threshold_string); | ||
71 | if (tmp.error != MP_PARSING_SUCCES) { | ||
72 | die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", threshold_string); | ||
73 | } | ||
74 | |||
75 | if (is_critical) { | ||
76 | test_units[0].threshold.critical = tmp.range; | ||
77 | test_units[0].threshold.critical_is_set = true; | ||
78 | } else { | ||
79 | test_units[0].threshold.warning = tmp.range; | ||
80 | test_units[0].threshold.warning_is_set = true; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | const int DEFAULT_PROTOCOL = SNMP_VERSION_1; | ||
88 | const char DEFAULT_OUTPUT_DELIMITER[] = " "; | ||
89 | |||
90 | const int RANDOM_STATE_DATA_LENGTH_PREDICTION = 8192; | ||
91 | |||
92 | check_snmp_config check_snmp_config_init() { | ||
93 | check_snmp_config tmp = { | ||
94 | .snmp_params = | ||
95 | { | ||
96 | .use_getnext = false, | ||
97 | |||
98 | .ignore_mib_parsing_errors = false, | ||
99 | .need_mibs = false, | ||
100 | |||
101 | .test_units = NULL, | ||
102 | .num_of_test_units = 0, | ||
103 | }, | ||
104 | |||
105 | .evaluation_params = | ||
106 | { | ||
107 | .nulloid_result = STATE_UNKNOWN, // state to return if no result for query | ||
108 | |||
109 | .invert_search = true, | ||
110 | .regex_cmp_value = {}, | ||
111 | .string_cmp_value = "", | ||
112 | |||
113 | .multiplier = 1.0, | ||
114 | .multiplier_set = false, | ||
115 | .offset = 0, | ||
116 | .offset_set = false, | ||
117 | |||
118 | .use_oid_as_perf_data_label = false, | ||
119 | |||
120 | .calculate_rate = false, | ||
121 | .rate_multiplier = 1, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | snmp_sess_init(&tmp.snmp_params.snmp_session); | ||
126 | |||
127 | tmp.snmp_params.snmp_session.retries = DEFAULT_RETRIES; | ||
128 | tmp.snmp_params.snmp_session.version = DEFAULT_SNMP_VERSION; | ||
129 | tmp.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH; | ||
130 | tmp.snmp_params.snmp_session.community = (unsigned char *)"public"; | ||
131 | tmp.snmp_params.snmp_session.community_len = strlen("public"); | ||
132 | return tmp; | ||
133 | } | ||
134 | |||
135 | snmp_responces do_snmp_query(check_snmp_config_snmp_parameters parameters) { | ||
136 | if (parameters.ignore_mib_parsing_errors) { | ||
137 | char *opt_toggle_res = snmp_mib_toggle_options("e"); | ||
138 | if (opt_toggle_res != NULL) { | ||
139 | die(STATE_UNKNOWN, "Unable to disable MIB parsing errors"); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | struct snmp_pdu *pdu = NULL; | ||
144 | if (parameters.use_getnext) { | ||
145 | pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); | ||
146 | } else { | ||
147 | pdu = snmp_pdu_create(SNMP_MSG_GET); | ||
148 | } | ||
149 | |||
150 | for (size_t i = 0; i < parameters.num_of_test_units; i++) { | ||
151 | assert(parameters.test_units[i].oid != NULL); | ||
152 | if (verbose > 0) { | ||
153 | printf("OID %zu to parse: %s\n", i, parameters.test_units[i].oid); | ||
154 | } | ||
155 | |||
156 | oid tmp_OID[MAX_OID_LEN]; | ||
157 | size_t tmp_OID_len = MAX_OID_LEN; | ||
158 | if (snmp_parse_oid(parameters.test_units[i].oid, tmp_OID, &tmp_OID_len) != NULL) { | ||
159 | // success | ||
160 | snmp_add_null_var(pdu, tmp_OID, tmp_OID_len); | ||
161 | } else { | ||
162 | // failed | ||
163 | snmp_perror("Parsing failure"); | ||
164 | die(STATE_UNKNOWN, "Failed to parse OID\n"); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | const int timeout_safety_tolerance = 5; | ||
169 | alarm((timeout_interval * (unsigned int)parameters.snmp_session.retries) + | ||
170 | timeout_safety_tolerance); | ||
171 | |||
172 | struct snmp_session *active_session = snmp_open(¶meters.snmp_session); | ||
173 | if (active_session == NULL) { | ||
174 | int pcliberr = 0; | ||
175 | int psnmperr = 0; | ||
176 | char *pperrstring = NULL; | ||
177 | snmp_error(¶meters.snmp_session, &pcliberr, &psnmperr, &pperrstring); | ||
178 | die(STATE_UNKNOWN, "Failed to open SNMP session: %s\n", pperrstring); | ||
179 | } | ||
180 | |||
181 | struct snmp_pdu *response = NULL; | ||
182 | int snmp_query_status = snmp_synch_response(active_session, pdu, &response); | ||
183 | |||
184 | if (!(snmp_query_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)) { | ||
185 | int pcliberr = 0; | ||
186 | int psnmperr = 0; | ||
187 | char *pperrstring = NULL; | ||
188 | snmp_error(active_session, &pcliberr, &psnmperr, &pperrstring); | ||
189 | |||
190 | if (psnmperr == SNMPERR_TIMEOUT) { | ||
191 | // We exit with critical here for some historical reason | ||
192 | die(STATE_CRITICAL, "SNMP query ran into a timeout\n"); | ||
193 | } | ||
194 | die(STATE_UNKNOWN, "SNMP query failed: %s\n", pperrstring); | ||
195 | } | ||
196 | |||
197 | snmp_close(active_session); | ||
198 | |||
199 | /* disable alarm again */ | ||
200 | alarm(0); | ||
201 | |||
202 | snmp_responces result = { | ||
203 | .errorcode = OK, | ||
204 | .response_values = calloc(parameters.num_of_test_units, sizeof(response_value)), | ||
205 | }; | ||
206 | |||
207 | if (result.response_values == NULL) { | ||
208 | result.errorcode = ERROR; | ||
209 | return result; | ||
210 | } | ||
211 | |||
212 | // We got the the query results, now process them | ||
213 | size_t loop_index = 0; | ||
214 | for (netsnmp_variable_list *vars = response->variables; vars; | ||
215 | vars = vars->next_variable, loop_index++) { | ||
216 | |||
217 | for (size_t jdx = 0; jdx < vars->name_length; jdx++) { | ||
218 | result.response_values[loop_index].oid[jdx] = vars->name[jdx]; | ||
219 | } | ||
220 | result.response_values[loop_index].oid_length = vars->name_length; | ||
221 | |||
222 | switch (vars->type) { | ||
223 | case ASN_OCTET_STR: { | ||
224 | result.response_values[loop_index].string_response = strdup((char *)vars->val.string); | ||
225 | result.response_values[loop_index].type = vars->type; | ||
226 | if (verbose) { | ||
227 | printf("Debug: Got a string as response: %s\n", vars->val.string); | ||
228 | } | ||
229 | } | ||
230 | continue; | ||
231 | case ASN_OPAQUE: | ||
232 | if (verbose) { | ||
233 | printf("Debug: Got OPAQUE\n"); | ||
234 | } | ||
235 | break; | ||
236 | /* Numerical values */ | ||
237 | case ASN_COUNTER64: { | ||
238 | if (verbose) { | ||
239 | printf("Debug: Got counter64\n"); | ||
240 | } | ||
241 | struct counter64 tmp = *(vars->val.counter64); | ||
242 | uint64_t counter = (tmp.high << 32) + tmp.low; | ||
243 | result.response_values[loop_index].value.uIntVal = counter; | ||
244 | result.response_values[loop_index].type = vars->type; | ||
245 | } break; | ||
246 | case ASN_GAUGE: // same as ASN_UNSIGNED | ||
247 | case ASN_TIMETICKS: | ||
248 | case ASN_COUNTER: | ||
249 | case ASN_UINTEGER: { | ||
250 | if (verbose) { | ||
251 | printf("Debug: Got a Integer like\n"); | ||
252 | } | ||
253 | result.response_values[loop_index].value.uIntVal = (unsigned long)*(vars->val.integer); | ||
254 | result.response_values[loop_index].type = vars->type; | ||
255 | } break; | ||
256 | case ASN_INTEGER: { | ||
257 | if (verbose) { | ||
258 | printf("Debug: Got a Integer\n"); | ||
259 | } | ||
260 | result.response_values[loop_index].value.intVal = *(vars->val.integer); | ||
261 | result.response_values[loop_index].type = vars->type; | ||
262 | } break; | ||
263 | case ASN_FLOAT: { | ||
264 | if (verbose) { | ||
265 | printf("Debug: Got a float\n"); | ||
266 | } | ||
267 | result.response_values[loop_index].value.doubleVal = *(vars->val.floatVal); | ||
268 | result.response_values[loop_index].type = vars->type; | ||
269 | } break; | ||
270 | case ASN_DOUBLE: { | ||
271 | if (verbose) { | ||
272 | printf("Debug: Got a double\n"); | ||
273 | } | ||
274 | result.response_values[loop_index].value.doubleVal = *(vars->val.doubleVal); | ||
275 | result.response_values[loop_index].type = vars->type; | ||
276 | } break; | ||
277 | case ASN_IPADDRESS: | ||
278 | if (verbose) { | ||
279 | printf("Debug: Got an IP address\n"); | ||
280 | } | ||
281 | result.response_values[loop_index].type = vars->type; | ||
282 | |||
283 | // TODO: print address here, state always ok? or regex match? | ||
284 | break; | ||
285 | default: | ||
286 | if (verbose) { | ||
287 | printf("Debug: Got a unmatched result type: %hhu\n", vars->type); | ||
288 | } | ||
289 | // TODO: Error here? | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return result; | ||
295 | } | ||
296 | |||
297 | check_snmp_evaluation evaluate_single_unit(response_value response, | ||
298 | check_snmp_evaluation_parameters eval_params, | ||
299 | check_snmp_test_unit test_unit, time_t query_timestamp, | ||
300 | check_snmp_state_entry prev_state, | ||
301 | bool have_previous_state) { | ||
302 | mp_subcheck sc_oid_test = mp_subcheck_init(); | ||
303 | |||
304 | if ((test_unit.label != NULL) && (strcmp(test_unit.label, "") != 0)) { | ||
305 | xasprintf(&sc_oid_test.output, "%s - ", test_unit.label); | ||
306 | } else { | ||
307 | sc_oid_test.output = strdup(""); | ||
308 | } | ||
309 | |||
310 | char oid_string[(MAX_OID_LEN * 2) + 1] = {}; | ||
311 | |||
312 | int oid_string_result = | ||
313 | snprint_objid(oid_string, (MAX_OID_LEN * 2) + 1, response.oid, response.oid_length); | ||
314 | if (oid_string_result <= 0) { | ||
315 | // TODO error here | ||
316 | die(STATE_UNKNOWN, "snprint_objid failed\n"); | ||
317 | } | ||
318 | |||
319 | xasprintf(&sc_oid_test.output, "%sOID: %s", sc_oid_test.output, oid_string); | ||
320 | sc_oid_test = mp_set_subcheck_default_state(sc_oid_test, STATE_OK); | ||
321 | |||
322 | if (verbose > 2) { | ||
323 | printf("Processing oid %s\n", oid_string); | ||
324 | } | ||
325 | |||
326 | bool got_a_numerical_value = false; | ||
327 | mp_perfdata_value pd_result_val = {0}; | ||
328 | |||
329 | check_snmp_state_entry result_state = { | ||
330 | .timestamp = query_timestamp, | ||
331 | .oid_length = response.oid_length, | ||
332 | .type = response.type, | ||
333 | }; | ||
334 | |||
335 | for (size_t i = 0; i < response.oid_length; i++) { | ||
336 | result_state.oid[i] = response.oid[i]; | ||
337 | } | ||
338 | |||
339 | if (have_previous_state) { | ||
340 | if (query_timestamp == prev_state.timestamp) { | ||
341 | // somehow we have the same timestamp again, that can't be good | ||
342 | sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_UNKNOWN); | ||
343 | xasprintf(&sc_oid_test.output, "Time duration between plugin calls is invalid"); | ||
344 | |||
345 | check_snmp_evaluation result = { | ||
346 | .sc = sc_oid_test, | ||
347 | .state = result_state, | ||
348 | }; | ||
349 | |||
350 | return result; | ||
351 | } | ||
352 | } | ||
353 | // compute rate time difference | ||
354 | double timeDiff = 0; | ||
355 | if (have_previous_state) { | ||
356 | if (verbose) { | ||
357 | printf("Previous timestamp: %s", ctime(&prev_state.timestamp)); | ||
358 | printf("Current timestamp: %s", ctime(&query_timestamp)); | ||
359 | } | ||
360 | timeDiff = difftime(query_timestamp, prev_state.timestamp) / eval_params.rate_multiplier; | ||
361 | } | ||
362 | |||
363 | mp_perfdata pd_num_val = {}; | ||
364 | |||
365 | switch (response.type) { | ||
366 | case ASN_OCTET_STR: { | ||
367 | char *tmp = response.string_response; | ||
368 | if (strchr(tmp, '"') != NULL) { | ||
369 | // got double quote in the string | ||
370 | if (strchr(tmp, '\'') != NULL) { | ||
371 | // got single quote in the string too | ||
372 | // dont quote that at all to avoid even more confusion | ||
373 | xasprintf(&sc_oid_test.output, "%s - Value: %s", sc_oid_test.output, tmp); | ||
374 | } else { | ||
375 | // quote with single quotes | ||
376 | xasprintf(&sc_oid_test.output, "%s - Value: '%s'", sc_oid_test.output, tmp); | ||
377 | } | ||
378 | } else { | ||
379 | // quote with double quotes | ||
380 | xasprintf(&sc_oid_test.output, "%s - Value: \"%s\"", sc_oid_test.output, tmp); | ||
381 | } | ||
382 | |||
383 | if (strlen(tmp) == 0) { | ||
384 | sc_oid_test = mp_set_subcheck_state(sc_oid_test, eval_params.nulloid_result); | ||
385 | } | ||
386 | |||
387 | // String matching test | ||
388 | if ((test_unit.eval_mthd.crit_string)) { | ||
389 | if (strcmp(tmp, eval_params.string_cmp_value)) { | ||
390 | sc_oid_test = mp_set_subcheck_state( | ||
391 | sc_oid_test, (eval_params.invert_search) ? STATE_CRITICAL : STATE_OK); | ||
392 | } else { | ||
393 | sc_oid_test = mp_set_subcheck_state( | ||
394 | sc_oid_test, (eval_params.invert_search) ? STATE_OK : STATE_CRITICAL); | ||
395 | } | ||
396 | } else if (test_unit.eval_mthd.crit_regex) { | ||
397 | const size_t nmatch = eval_params.regex_cmp_value.re_nsub + 1; | ||
398 | regmatch_t pmatch[nmatch]; | ||
399 | memset(pmatch, '\0', sizeof(regmatch_t) * nmatch); | ||
400 | |||
401 | int excode = regexec(&eval_params.regex_cmp_value, tmp, nmatch, pmatch, 0); | ||
402 | if (excode == 0) { | ||
403 | sc_oid_test = mp_set_subcheck_state( | ||
404 | sc_oid_test, (eval_params.invert_search) ? STATE_OK : STATE_CRITICAL); | ||
405 | } else if (excode != REG_NOMATCH) { | ||
406 | char errbuf[MAX_INPUT_BUFFER] = ""; | ||
407 | regerror(excode, &eval_params.regex_cmp_value, errbuf, MAX_INPUT_BUFFER); | ||
408 | printf(_("Execute Error: %s\n"), errbuf); | ||
409 | exit(STATE_CRITICAL); | ||
410 | } else { // REG_NOMATCH | ||
411 | sc_oid_test = mp_set_subcheck_state( | ||
412 | sc_oid_test, eval_params.invert_search ? STATE_CRITICAL : STATE_OK); | ||
413 | } | ||
414 | } | ||
415 | } break; | ||
416 | case ASN_COUNTER64: | ||
417 | got_a_numerical_value = true; | ||
418 | |||
419 | result_state.value.uIntVal = response.value.uIntVal; | ||
420 | result_state.type = response.type; | ||
421 | |||
422 | // TODO: perfdata unit counter | ||
423 | if (eval_params.calculate_rate && have_previous_state) { | ||
424 | if (prev_state.value.uIntVal > response.value.uIntVal) { | ||
425 | // overflow | ||
426 | unsigned long long tmp = | ||
427 | (UINT64_MAX - prev_state.value.uIntVal) + response.value.uIntVal; | ||
428 | |||
429 | tmp /= timeDiff; | ||
430 | pd_result_val = mp_create_pd_value(tmp); | ||
431 | } else { | ||
432 | pd_result_val = mp_create_pd_value( | ||
433 | (response.value.uIntVal - prev_state.value.uIntVal) / timeDiff); | ||
434 | } | ||
435 | } else { | ||
436 | // It's only a counter if we cont compute rate | ||
437 | pd_num_val.uom = "c"; | ||
438 | pd_result_val = mp_create_pd_value(response.value.uIntVal); | ||
439 | } | ||
440 | break; | ||
441 | case ASN_GAUGE: // same as ASN_UNSIGNED | ||
442 | case ASN_TIMETICKS: | ||
443 | case ASN_COUNTER: | ||
444 | case ASN_UINTEGER: { | ||
445 | got_a_numerical_value = true; | ||
446 | long long treated_value = (long long)response.value.uIntVal; | ||
447 | |||
448 | if (eval_params.multiplier_set || eval_params.offset_set) { | ||
449 | double processed = 0; | ||
450 | if (eval_params.offset_set) { | ||
451 | processed += eval_params.offset; | ||
452 | } | ||
453 | |||
454 | if (eval_params.multiplier_set) { | ||
455 | processed = processed * eval_params.multiplier; | ||
456 | } | ||
457 | |||
458 | treated_value = lround(processed); | ||
459 | } | ||
460 | |||
461 | result_state.value.intVal = treated_value; | ||
462 | |||
463 | if (eval_params.calculate_rate && have_previous_state) { | ||
464 | if (verbose > 2) { | ||
465 | printf("%s: Rate calculation (int/counter/gauge): prev: %lli\n", __FUNCTION__, | ||
466 | prev_state.value.intVal); | ||
467 | printf("%s: Rate calculation (int/counter/gauge): current: %lli\n", __FUNCTION__, | ||
468 | treated_value); | ||
469 | } | ||
470 | double rate = (treated_value - prev_state.value.intVal) / timeDiff; | ||
471 | pd_result_val = mp_create_pd_value(rate); | ||
472 | } else { | ||
473 | pd_result_val = mp_create_pd_value(treated_value); | ||
474 | |||
475 | if (response.type == ASN_COUNTER) { | ||
476 | pd_num_val.uom = "c"; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | } break; | ||
481 | case ASN_INTEGER: { | ||
482 | if (eval_params.multiplier_set || eval_params.offset_set) { | ||
483 | double processed = 0; | ||
484 | if (eval_params.multiplier_set) { | ||
485 | processed = (double)response.value.intVal * eval_params.multiplier; | ||
486 | } | ||
487 | |||
488 | if (eval_params.offset_set) { | ||
489 | processed += eval_params.offset; | ||
490 | } | ||
491 | |||
492 | result_state.value.doubleVal = processed; | ||
493 | |||
494 | if (eval_params.calculate_rate && have_previous_state) { | ||
495 | pd_result_val = | ||
496 | mp_create_pd_value((processed - prev_state.value.doubleVal) / timeDiff); | ||
497 | } else { | ||
498 | pd_result_val = mp_create_pd_value(processed); | ||
499 | } | ||
500 | } else { | ||
501 | result_state.value.intVal = response.value.intVal; | ||
502 | |||
503 | if (eval_params.calculate_rate && have_previous_state) { | ||
504 | pd_result_val = mp_create_pd_value( | ||
505 | (response.value.intVal - prev_state.value.intVal) / timeDiff); | ||
506 | } else { | ||
507 | pd_result_val = mp_create_pd_value(response.value.intVal); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | got_a_numerical_value = true; | ||
512 | } break; | ||
513 | case ASN_FLOAT: // fallthrough | ||
514 | case ASN_DOUBLE: { | ||
515 | got_a_numerical_value = true; | ||
516 | double tmp = response.value.doubleVal; | ||
517 | if (eval_params.offset_set) { | ||
518 | tmp += eval_params.offset; | ||
519 | } | ||
520 | |||
521 | if (eval_params.multiplier_set) { | ||
522 | tmp *= eval_params.multiplier; | ||
523 | } | ||
524 | |||
525 | if (eval_params.calculate_rate && have_previous_state) { | ||
526 | pd_result_val = mp_create_pd_value((tmp - prev_state.value.doubleVal) / timeDiff); | ||
527 | } else { | ||
528 | pd_result_val = mp_create_pd_value(tmp); | ||
529 | } | ||
530 | got_a_numerical_value = true; | ||
531 | |||
532 | result_state.value.doubleVal = tmp; | ||
533 | } break; | ||
534 | case ASN_IPADDRESS: | ||
535 | // TODO | ||
536 | break; | ||
537 | } | ||
538 | |||
539 | if (got_a_numerical_value) { | ||
540 | if (eval_params.use_oid_as_perf_data_label) { | ||
541 | // Use oid for perdata label | ||
542 | pd_num_val.label = strdup(oid_string); | ||
543 | // TODO strdup error checking | ||
544 | } else if (test_unit.label != NULL && strcmp(test_unit.label, "") != 0) { | ||
545 | pd_num_val.label = strdup(test_unit.label); | ||
546 | } else { | ||
547 | pd_num_val.label = strdup(test_unit.oid); | ||
548 | } | ||
549 | |||
550 | if (!(eval_params.calculate_rate && !have_previous_state)) { | ||
551 | // some kind of numerical value | ||
552 | if (test_unit.unit_value != NULL && strcmp(test_unit.unit_value, "") != 0) { | ||
553 | pd_num_val.uom = test_unit.unit_value; | ||
554 | } | ||
555 | |||
556 | pd_num_val.value = pd_result_val; | ||
557 | |||
558 | xasprintf(&sc_oid_test.output, "%s Value: %s", sc_oid_test.output, | ||
559 | pd_value_to_string(pd_result_val)); | ||
560 | |||
561 | if (test_unit.unit_value != NULL && strcmp(test_unit.unit_value, "") != 0) { | ||
562 | xasprintf(&sc_oid_test.output, "%s%s", sc_oid_test.output, test_unit.unit_value); | ||
563 | } | ||
564 | |||
565 | if (test_unit.threshold.warning_is_set || test_unit.threshold.critical_is_set) { | ||
566 | pd_num_val = mp_pd_set_thresholds(pd_num_val, test_unit.threshold); | ||
567 | mp_state_enum tmp_state = mp_get_pd_status(pd_num_val); | ||
568 | |||
569 | if (tmp_state == STATE_WARNING) { | ||
570 | sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_WARNING); | ||
571 | xasprintf(&sc_oid_test.output, "%s - number violates warning threshold", | ||
572 | sc_oid_test.output); | ||
573 | } else if (tmp_state == STATE_CRITICAL) { | ||
574 | sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_CRITICAL); | ||
575 | xasprintf(&sc_oid_test.output, "%s - number violates critical threshold", | ||
576 | sc_oid_test.output); | ||
577 | } | ||
578 | } | ||
579 | |||
580 | mp_add_perfdata_to_subcheck(&sc_oid_test, pd_num_val); | ||
581 | } else { | ||
582 | // should calculate rate, but there is no previous state, so first run | ||
583 | // exit with ok now | ||
584 | sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_OK); | ||
585 | xasprintf(&sc_oid_test.output, "%s - No previous data to calculate rate - assume okay", | ||
586 | sc_oid_test.output); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | check_snmp_evaluation result = { | ||
591 | .sc = sc_oid_test, | ||
592 | .state = result_state, | ||
593 | }; | ||
594 | |||
595 | return result; | ||
596 | } | ||
597 | |||
598 | char *_np_state_generate_key(int argc, char **argv); | ||
599 | |||
600 | /* | ||
601 | * If time=NULL, use current time. Create state file, with state format | ||
602 | * version, default text. Writes version, time, and data. Avoid locking | ||
603 | * problems - use mv to write and then swap. Possible loss of state data if | ||
604 | * two things writing to same key at same time. | ||
605 | * Will die with UNKNOWN if errors | ||
606 | */ | ||
607 | void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore) { | ||
608 | time_t current_time; | ||
609 | if (timestamp == 0) { | ||
610 | time(¤t_time); | ||
611 | } else { | ||
612 | current_time = timestamp; | ||
613 | } | ||
614 | |||
615 | int result = 0; | ||
616 | |||
617 | /* If file doesn't currently exist, create directories */ | ||
618 | if (access(stateKey._filename, F_OK) != 0) { | ||
619 | char *directories = NULL; | ||
620 | result = asprintf(&directories, "%s", stateKey._filename); | ||
621 | if (result < 0) { | ||
622 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
623 | } | ||
624 | |||
625 | for (char *p = directories + 1; *p; p++) { | ||
626 | if (*p == '/') { | ||
627 | *p = '\0'; | ||
628 | if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) { | ||
629 | /* Can't free this! Otherwise error message is wrong! */ | ||
630 | /* np_free(directories); */ | ||
631 | die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); | ||
632 | } | ||
633 | *p = '/'; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | if (directories) { | ||
638 | free(directories); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | char *temp_file = NULL; | ||
643 | result = asprintf(&temp_file, "%s.XXXXXX", stateKey._filename); | ||
644 | if (result < 0) { | ||
645 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
646 | } | ||
647 | |||
648 | int temp_file_desc = 0; | ||
649 | if ((temp_file_desc = mkstemp(temp_file)) == -1) { | ||
650 | if (temp_file) { | ||
651 | free(temp_file); | ||
652 | } | ||
653 | die(STATE_UNKNOWN, _("Cannot create temporary filename")); | ||
654 | } | ||
655 | |||
656 | FILE *temp_file_pointer = fdopen(temp_file_desc, "w"); | ||
657 | if (temp_file_pointer == NULL) { | ||
658 | close(temp_file_desc); | ||
659 | unlink(temp_file); | ||
660 | if (temp_file) { | ||
661 | free(temp_file); | ||
662 | } | ||
663 | die(STATE_UNKNOWN, _("Unable to open temporary state file")); | ||
664 | } | ||
665 | |||
666 | fprintf(temp_file_pointer, "# NP State file\n"); | ||
667 | fprintf(temp_file_pointer, "%d\n", NP_STATE_FORMAT_VERSION); | ||
668 | fprintf(temp_file_pointer, "%d\n", stateKey.data_version); | ||
669 | fprintf(temp_file_pointer, "%lu\n", current_time); | ||
670 | fprintf(temp_file_pointer, "%s\n", stringToStore); | ||
671 | |||
672 | fchmod(temp_file_desc, S_IRUSR | S_IWUSR | S_IRGRP); | ||
673 | |||
674 | fflush(temp_file_pointer); | ||
675 | |||
676 | result = fclose(temp_file_pointer); | ||
677 | |||
678 | fsync(temp_file_desc); | ||
679 | |||
680 | if (result != 0) { | ||
681 | unlink(temp_file); | ||
682 | if (temp_file) { | ||
683 | free(temp_file); | ||
684 | } | ||
685 | die(STATE_UNKNOWN, _("Error writing temp file")); | ||
686 | } | ||
687 | |||
688 | if (rename(temp_file, stateKey._filename) != 0) { | ||
689 | unlink(temp_file); | ||
690 | if (temp_file) { | ||
691 | free(temp_file); | ||
692 | } | ||
693 | die(STATE_UNKNOWN, _("Cannot rename state temp file")); | ||
694 | } | ||
695 | |||
696 | if (temp_file) { | ||
697 | free(temp_file); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * Read the state file | ||
703 | */ | ||
704 | bool _np_state_read_file(FILE *state_file, state_key stateKey) { | ||
705 | time_t current_time; | ||
706 | time(¤t_time); | ||
707 | |||
708 | /* Note: This introduces a limit of 8192 bytes in the string data */ | ||
709 | char *line = (char *)calloc(1, 8192); | ||
710 | if (line == NULL) { | ||
711 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
712 | } | ||
713 | |||
714 | bool status = false; | ||
715 | enum { | ||
716 | STATE_FILE_VERSION, | ||
717 | STATE_DATA_VERSION, | ||
718 | STATE_DATA_TIME, | ||
719 | STATE_DATA_TEXT, | ||
720 | STATE_DATA_END | ||
721 | } expected = STATE_FILE_VERSION; | ||
722 | |||
723 | int failure = 0; | ||
724 | while (!failure && (fgets(line, 8192, state_file)) != NULL) { | ||
725 | size_t pos = strlen(line); | ||
726 | if (line[pos - 1] == '\n') { | ||
727 | line[pos - 1] = '\0'; | ||
728 | } | ||
729 | |||
730 | if (line[0] == '#') { | ||
731 | continue; | ||
732 | } | ||
733 | |||
734 | switch (expected) { | ||
735 | case STATE_FILE_VERSION: { | ||
736 | int i = atoi(line); | ||
737 | if (i != NP_STATE_FORMAT_VERSION) { | ||
738 | failure++; | ||
739 | } else { | ||
740 | expected = STATE_DATA_VERSION; | ||
741 | } | ||
742 | } break; | ||
743 | case STATE_DATA_VERSION: { | ||
744 | int i = atoi(line); | ||
745 | if (i != stateKey.data_version) { | ||
746 | failure++; | ||
747 | } else { | ||
748 | expected = STATE_DATA_TIME; | ||
749 | } | ||
750 | } break; | ||
751 | case STATE_DATA_TIME: { | ||
752 | /* If time > now, error */ | ||
753 | time_t data_time = strtoul(line, NULL, 10); | ||
754 | if (data_time > current_time) { | ||
755 | failure++; | ||
756 | } else { | ||
757 | stateKey.state_data->time = data_time; | ||
758 | expected = STATE_DATA_TEXT; | ||
759 | } | ||
760 | } break; | ||
761 | case STATE_DATA_TEXT: | ||
762 | stateKey.state_data->data = strdup(line); | ||
763 | if (stateKey.state_data->data == NULL) { | ||
764 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | ||
765 | } | ||
766 | stateKey.state_data->length = strlen(line); | ||
767 | expected = STATE_DATA_END; | ||
768 | status = true; | ||
769 | break; | ||
770 | case STATE_DATA_END:; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | if (line) { | ||
775 | free(line); | ||
776 | } | ||
777 | return status; | ||
778 | } | ||
779 | /* | ||
780 | * Will return NULL if no data is available (first run). If key currently | ||
781 | * exists, read data. If state file format version is not expected, return | ||
782 | * as if no data. Get state data version number and compares to expected. | ||
783 | * If numerically lower, then return as no previous state. die with UNKNOWN | ||
784 | * if exceptional error. | ||
785 | */ | ||
786 | state_data *np_state_read(state_key stateKey) { | ||
787 | /* Open file. If this fails, no previous state found */ | ||
788 | FILE *statefile = fopen(stateKey._filename, "r"); | ||
789 | state_data *this_state_data = (state_data *)calloc(1, sizeof(state_data)); | ||
790 | if (statefile != NULL) { | ||
791 | |||
792 | if (this_state_data == NULL) { | ||
793 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
794 | } | ||
795 | |||
796 | this_state_data->data = NULL; | ||
797 | stateKey.state_data = this_state_data; | ||
798 | |||
799 | if (_np_state_read_file(statefile, stateKey)) { | ||
800 | this_state_data->errorcode = OK; | ||
801 | } else { | ||
802 | this_state_data->errorcode = ERROR; | ||
803 | } | ||
804 | |||
805 | fclose(statefile); | ||
806 | } else { | ||
807 | // Failed to open state file | ||
808 | this_state_data->errorcode = ERROR; | ||
809 | } | ||
810 | |||
811 | return stateKey.state_data; | ||
812 | } | ||
813 | |||
814 | /* | ||
815 | * Internal function. Returns either: | ||
816 | * envvar NAGIOS_PLUGIN_STATE_DIRECTORY | ||
817 | * statically compiled shared state directory | ||
818 | */ | ||
819 | char *_np_state_calculate_location_prefix(void) { | ||
820 | char *env_dir; | ||
821 | |||
822 | /* Do not allow passing MP_STATE_PATH in setuid plugins | ||
823 | * for security reasons */ | ||
824 | if (!mp_suid()) { | ||
825 | env_dir = getenv("MP_STATE_PATH"); | ||
826 | if (env_dir && env_dir[0] != '\0') { | ||
827 | return env_dir; | ||
828 | } | ||
829 | /* This is the former ENV, for backward-compatibility */ | ||
830 | env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY"); | ||
831 | if (env_dir && env_dir[0] != '\0') { | ||
832 | return env_dir; | ||
833 | } | ||
834 | } | ||
835 | |||
836 | return NP_STATE_DIR_PREFIX; | ||
837 | } | ||
838 | |||
839 | /* | ||
840 | * Initiatializer for state routines. | ||
841 | * Sets variables. Generates filename. Returns np_state_key. die with | ||
842 | * UNKNOWN if exception | ||
843 | */ | ||
844 | state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc, | ||
845 | char **argv) { | ||
846 | state_key *this_state = (state_key *)calloc(1, sizeof(state_key)); | ||
847 | if (this_state == NULL) { | ||
848 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
849 | } | ||
850 | |||
851 | char *temp_keyname = NULL; | ||
852 | if (keyname == NULL) { | ||
853 | temp_keyname = _np_state_generate_key(argc, argv); | ||
854 | } else { | ||
855 | temp_keyname = strdup(keyname); | ||
856 | if (temp_keyname == NULL) { | ||
857 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | /* Die if invalid characters used for keyname */ | ||
862 | char *tmp_char = temp_keyname; | ||
863 | while (*tmp_char != '\0') { | ||
864 | if (!(isalnum(*tmp_char) || *tmp_char == '_')) { | ||
865 | die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'")); | ||
866 | } | ||
867 | tmp_char++; | ||
868 | } | ||
869 | this_state->name = temp_keyname; | ||
870 | this_state->plugin_name = plugin_name; | ||
871 | this_state->data_version = expected_data_version; | ||
872 | this_state->state_data = NULL; | ||
873 | |||
874 | /* Calculate filename */ | ||
875 | char *temp_filename = NULL; | ||
876 | int error = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), | ||
877 | (unsigned long)geteuid(), plugin_name, this_state->name); | ||
878 | if (error < 0) { | ||
879 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | ||
880 | } | ||
881 | |||
882 | this_state->_filename = temp_filename; | ||
883 | |||
884 | return *this_state; | ||
885 | } | ||
886 | |||
887 | /* | ||
888 | * Returns a string to use as a keyname, based on an md5 hash of argv, thus | ||
889 | * hopefully a unique key per service/plugin invocation. Use the extra-opts | ||
890 | * parse of argv, so that uniqueness in parameters are reflected there. | ||
891 | */ | ||
892 | char *_np_state_generate_key(int argc, char **argv) { | ||
893 | unsigned char result[256]; | ||
894 | |||
895 | #ifdef USE_OPENSSL | ||
896 | /* | ||
897 | * This code path is chosen if openssl is available (which should be the most common | ||
898 | * scenario). Alternatively, the gnulib implementation/ | ||
899 | * | ||
900 | */ | ||
901 | EVP_MD_CTX *ctx = EVP_MD_CTX_new(); | ||
902 | |||
903 | EVP_DigestInit(ctx, EVP_sha256()); | ||
904 | |||
905 | for (int i = 0; i < argc; i++) { | ||
906 | EVP_DigestUpdate(ctx, argv[i], strlen(argv[i])); | ||
907 | } | ||
908 | |||
909 | EVP_DigestFinal(ctx, result, NULL); | ||
910 | #else | ||
911 | |||
912 | struct sha256_ctx ctx; | ||
913 | |||
914 | for (int i = 0; i < this_monitoring_plugin->argc; i++) { | ||
915 | sha256_process_bytes(argv[i], strlen(argv[i]), &ctx); | ||
916 | } | ||
917 | |||
918 | sha256_finish_ctx(&ctx, result); | ||
919 | #endif // FOUNDOPENSSL | ||
920 | |||
921 | char keyname[41]; | ||
922 | for (int i = 0; i < 20; ++i) { | ||
923 | sprintf(&keyname[2 * i], "%02x", result[i]); | ||
924 | } | ||
925 | |||
926 | keyname[40] = '\0'; | ||
927 | |||
928 | char *keyname_copy = strdup(keyname); | ||
929 | if (keyname_copy == NULL) { | ||
930 | die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); | ||
931 | } | ||
932 | |||
933 | return keyname_copy; | ||
934 | } | ||
diff --git a/plugins/check_snmp.d/check_snmp_helpers.h b/plugins/check_snmp.d/check_snmp_helpers.h new file mode 100644 index 00000000..0f7780b1 --- /dev/null +++ b/plugins/check_snmp.d/check_snmp_helpers.h | |||
@@ -0,0 +1,71 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "./config.h" | ||
4 | #include <net-snmp/library/asn1.h> | ||
5 | |||
6 | check_snmp_test_unit check_snmp_test_unit_init(); | ||
7 | int check_snmp_set_thresholds(const char *, check_snmp_test_unit[], size_t, bool); | ||
8 | check_snmp_config check_snmp_config_init(); | ||
9 | |||
10 | typedef struct { | ||
11 | oid oid[MAX_OID_LEN]; | ||
12 | size_t oid_length; | ||
13 | unsigned char type; | ||
14 | union { | ||
15 | uint64_t uIntVal; | ||
16 | int64_t intVal; | ||
17 | double doubleVal; | ||
18 | } value; | ||
19 | char *string_response; | ||
20 | } response_value; | ||
21 | |||
22 | typedef struct { | ||
23 | int errorcode; | ||
24 | response_value *response_values; | ||
25 | } snmp_responces; | ||
26 | snmp_responces do_snmp_query(check_snmp_config_snmp_parameters parameters); | ||
27 | |||
28 | // state is similar to response, but only numerics and a timestamp | ||
29 | typedef struct { | ||
30 | time_t timestamp; | ||
31 | oid oid[MAX_OID_LEN]; | ||
32 | size_t oid_length; | ||
33 | unsigned char type; | ||
34 | union { | ||
35 | unsigned long long uIntVal; | ||
36 | long long intVal; | ||
37 | double doubleVal; | ||
38 | } value; | ||
39 | } check_snmp_state_entry; | ||
40 | |||
41 | typedef struct { | ||
42 | check_snmp_state_entry state; | ||
43 | mp_subcheck sc; | ||
44 | } check_snmp_evaluation; | ||
45 | check_snmp_evaluation evaluate_single_unit(response_value response, | ||
46 | check_snmp_evaluation_parameters eval_params, | ||
47 | check_snmp_test_unit test_unit, time_t query_timestamp, | ||
48 | check_snmp_state_entry prev_state, | ||
49 | bool have_previous_state); | ||
50 | |||
51 | #define NP_STATE_FORMAT_VERSION 1 | ||
52 | |||
53 | typedef struct state_data_struct { | ||
54 | time_t time; | ||
55 | void *data; | ||
56 | size_t length; /* Of binary data */ | ||
57 | int errorcode; | ||
58 | } state_data; | ||
59 | |||
60 | typedef struct state_key_struct { | ||
61 | char *name; | ||
62 | char *plugin_name; | ||
63 | int data_version; | ||
64 | char *_filename; | ||
65 | state_data *state_data; | ||
66 | } state_key; | ||
67 | |||
68 | state_data *np_state_read(state_key stateKey); | ||
69 | state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc, | ||
70 | char **argv); | ||
71 | void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore); | ||
diff --git a/plugins/check_snmp.d/config.h b/plugins/check_snmp.d/config.h new file mode 100644 index 00000000..e7b6d1b3 --- /dev/null +++ b/plugins/check_snmp.d/config.h | |||
@@ -0,0 +1,81 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include "../../lib/thresholds.h" | ||
4 | #include "../../lib/states.h" | ||
5 | #include <stdlib.h> | ||
6 | #include <stdbool.h> | ||
7 | #include <regex.h> | ||
8 | #include "../common.h" | ||
9 | |||
10 | // defines for snmp libs | ||
11 | #define u_char unsigned char | ||
12 | #define u_long unsigned long | ||
13 | #define u_short unsigned short | ||
14 | #define u_int unsigned int | ||
15 | |||
16 | #include <net-snmp/net-snmp-config.h> | ||
17 | #include <net-snmp/net-snmp-includes.h> | ||
18 | #include <net-snmp/library/snmp.h> | ||
19 | #include <net-snmp/session_api.h> | ||
20 | |||
21 | #define DEFAULT_PORT "161" | ||
22 | #define DEFAULT_RETRIES 5 | ||
23 | |||
24 | typedef struct eval_method { | ||
25 | bool crit_string; | ||
26 | bool crit_regex; | ||
27 | } eval_method; | ||
28 | |||
29 | typedef struct check_snmp_test_unit { | ||
30 | char *oid; | ||
31 | char *label; | ||
32 | char *unit_value; | ||
33 | eval_method eval_mthd; | ||
34 | mp_thresholds threshold; | ||
35 | } check_snmp_test_unit; | ||
36 | |||
37 | typedef struct { | ||
38 | struct snmp_session snmp_session; | ||
39 | // use getnet instead of get | ||
40 | bool use_getnext; | ||
41 | |||
42 | // TODO actually make these useful | ||
43 | bool ignore_mib_parsing_errors; | ||
44 | bool need_mibs; | ||
45 | |||
46 | check_snmp_test_unit *test_units; | ||
47 | size_t num_of_test_units; | ||
48 | } check_snmp_config_snmp_parameters; | ||
49 | |||
50 | typedef struct { | ||
51 | // State if an empty value is encountered | ||
52 | mp_state_enum nulloid_result; | ||
53 | |||
54 | // String evaluation stuff | ||
55 | bool invert_search; | ||
56 | regex_t regex_cmp_value; // regex to match query results against | ||
57 | char string_cmp_value[MAX_INPUT_BUFFER]; | ||
58 | |||
59 | // Modify data | ||
60 | double multiplier; | ||
61 | bool multiplier_set; | ||
62 | double offset; | ||
63 | bool offset_set; | ||
64 | |||
65 | // Modify output | ||
66 | bool use_oid_as_perf_data_label; | ||
67 | |||
68 | // activate rate calculation | ||
69 | bool calculate_rate; | ||
70 | unsigned int rate_multiplier; | ||
71 | } check_snmp_evaluation_parameters; | ||
72 | |||
73 | typedef struct check_snmp_config { | ||
74 | // SNMP session to use | ||
75 | check_snmp_config_snmp_parameters snmp_params; | ||
76 | |||
77 | check_snmp_evaluation_parameters evaluation_params; | ||
78 | |||
79 | mp_output_format output_format; | ||
80 | bool output_format_is_set; | ||
81 | } check_snmp_config; | ||
diff --git a/plugins/t/check_snmp.t b/plugins/t/check_snmp.t index 576cc506..8d435df3 100644 --- a/plugins/t/check_snmp.t +++ b/plugins/t/check_snmp.t | |||
@@ -10,7 +10,7 @@ use NPTest; | |||
10 | 10 | ||
11 | BEGIN { | 11 | BEGIN { |
12 | plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp"; | 12 | plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp"; |
13 | plan tests => 63; | 13 | plan tests => 62; |
14 | } | 14 | } |
15 | 15 | ||
16 | my $res; | 16 | my $res; |
@@ -24,7 +24,7 @@ my $user_snmp = getTestParameter("NP_SNMP_USER", "An SNMP user", "auth_ | |||
24 | 24 | ||
25 | $res = NPTest->testCmd( "./check_snmp -t 1" ); | 25 | $res = NPTest->testCmd( "./check_snmp -t 1" ); |
26 | is( $res->return_code, 3, "No host name" ); | 26 | is( $res->return_code, 3, "No host name" ); |
27 | is( $res->output, "No host specified" ); | 27 | is( $res->output, "No OIDs specified" ); |
28 | 28 | ||
29 | $res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" ); | 29 | $res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" ); |
30 | is( $res->return_code, 3, "No OIDs specified" ); | 30 | is( $res->return_code, 3, "No OIDs specified" ); |
@@ -32,145 +32,124 @@ is( $res->output, "No OIDs specified" ); | |||
32 | 32 | ||
33 | $res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" ); | 33 | $res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" ); |
34 | is( $res->return_code, 3, "Invalid seclevel" ); | 34 | is( $res->return_code, 3, "Invalid seclevel" ); |
35 | like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" ); | 35 | like( $res->output, "/invalid security level: rubbish/" ); |
36 | 36 | ||
37 | $res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" ); | 37 | $res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" ); |
38 | is( $res->return_code, 3, "Invalid protocol" ); | 38 | is( $res->return_code, 3, "Invalid protocol" ); |
39 | like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" ); | 39 | like( $res->output, "/invalid SNMP version/protocol: 3c/" ); |
40 | 40 | ||
41 | SKIP: { | 41 | SKIP: { |
42 | skip "no snmp host defined", 50 if ( ! $host_snmp ); | 42 | skip "no snmp host defined", 50 if ( ! $host_snmp ); |
43 | 43 | ||
44 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); | 44 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -P 2c -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); |
45 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" ); | 45 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" ); |
46 | like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK"); | 46 | $res->output =~ /\|.*=(\d+);/; |
47 | $res->output =~ /^SNMP OK - (\d+)/; | ||
48 | my $value = $1; | 47 | my $value = $1; |
49 | cmp_ok( $value, ">", 0, "Got a time value" ); | 48 | cmp_ok( $value, ">", 0, "Got a time value" ); |
50 | like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it"); | 49 | like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it"); |
51 | 50 | ||
52 | 51 | ||
53 | # some more threshold tests | 52 | # some more threshold tests |
54 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1"); | 53 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1 -P 2c"); |
55 | cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" ); | 54 | cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" ); |
56 | 55 | ||
57 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:"); | 56 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1: -P 2c"); |
58 | cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" ); | 57 | cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" ); |
59 | 58 | ||
60 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1"); | 59 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1 -P 2c"); |
61 | cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" ); | 60 | cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" ); |
62 | 61 | ||
63 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10"); | 62 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10 -P 2c"); |
64 | cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" ); | 63 | cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" ); |
65 | 64 | ||
66 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10"); | 65 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10 -P 2c"); |
67 | cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" ); | 66 | cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" ); |
68 | 67 | ||
69 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 10:1"); | ||
70 | cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" ); | ||
71 | |||
72 | 68 | ||
73 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1:"); | 69 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1: -P 2c"); |
74 | cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" ); | 70 | cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" ); |
75 | like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK"); | ||
76 | 71 | ||
77 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0"); | 72 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -P 2c"); |
78 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" ); | 73 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" ); |
79 | unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values"); | 74 | unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values"); |
80 | 75 | ||
81 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0"); | 76 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0 -P 2c"); |
82 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" ); | 77 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" ); |
83 | like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); | ||
84 | 78 | ||
85 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0"); | 79 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0 -P 2c"); |
86 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" ); | 80 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" ); |
87 | like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); | ||
88 | 81 | ||
89 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1"); | 82 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1 -P 2c"); |
90 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" ); | 83 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" ); |
91 | like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format"); | ||
92 | 84 | ||
93 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1:"); | 85 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1: -P 2c"); |
94 | cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " ); | 86 | cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " ); |
95 | like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format"); | ||
96 | 87 | ||
97 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0"); | 88 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0 -P 2c"); |
98 | cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" ); | 89 | cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" ); |
99 | like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format"); | ||
100 | 90 | ||
101 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2"); | 91 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2 -P 2c"); |
102 | cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" ); | 92 | cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" ); |
103 | like($res->output, "/^SNMP OK - 2 1/", "Got two values back" ); | 93 | like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" ); |
104 | like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); | 94 | like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" ); |
105 | like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" ); | ||
106 | 95 | ||
107 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2"); | 96 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2 -P 2c"); |
108 | cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" ); | 97 | cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" ); |
109 | like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" ); | 98 | like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" ); |
110 | like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); | 99 | like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" ); |
111 | like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" ); | ||
112 | 100 | ||
113 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1:"); | 101 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1: -P 2c"); |
114 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses"); | 102 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses"); |
115 | like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses"); | ||
116 | 103 | ||
117 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0"); | 104 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0 -P 2c"); |
118 | cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds"); | 105 | cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds"); |
119 | like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format"); | ||
120 | 106 | ||
121 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3"); | 107 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -P 2c"); |
122 | $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/; | 108 | $res->output =~ m/^.*Value: (\d+).*$/; |
123 | my $lower = $1 - 0.05; | 109 | my $lower = $1 - 0.05; |
124 | my $higher = $1 + 0.05; | 110 | my $higher = $1 + 0.05; |
125 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3 -w $lower -c $higher"); | 111 | # $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -w $lower -c $higher -P 2c"); |
126 | cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments"); | 112 | # cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractional arguments"); |
127 | 113 | ||
128 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2"); | 114 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2 -P 2c"); |
129 | cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold"); | 115 | cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold"); |
130 | like($res->output, '/^SNMP WARNING - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s+\*1\*\s.*$/', "First OID returned as string, 2nd checked for thresholds"); | ||
131 | 116 | ||
132 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c ''"); | 117 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c '' -P 2c"); |
133 | cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash"); | 118 | cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash"); |
134 | 119 | ||
135 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2"); | 120 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2 -P 2c"); |
136 | cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check"); | 121 | cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check"); |
137 | like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed"); | ||
138 | 122 | ||
139 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,,"); | 123 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,, -P 2c"); |
140 | cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds"); | 124 | cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds"); |
141 | like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed"); | ||
142 | 125 | ||
143 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec'"); | 126 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec' -P 2c"); |
144 | cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold"); | 127 | cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold"); |
145 | like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric"); | ||
146 | 128 | ||
147 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0"); | 129 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -P 2c"); |
148 | cmp_ok( $res->return_code, '==', 0, "Timetick used as a string"); | 130 | cmp_ok( $res->return_code, '==', 0, "Timetick used as a string"); |
149 | like($res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "Timetick used as a string, result printed rather than parsed"); | ||
150 | 131 | ||
151 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1"); | 132 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1 -P 2c"); |
152 | cmp_ok( $res->return_code, '==', 0, "snmp response without datatype"); | 133 | cmp_ok( $res->return_code, '==', 0, "snmp response without datatype"); |
153 | like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" ); | ||
154 | } | 134 | } |
155 | 135 | ||
156 | SKIP: { | 136 | SKIP: { |
157 | skip "no SNMP user defined", 1 if ( ! $user_snmp ); | 137 | skip "no SNMP user defined", 1 if ( ! $user_snmp ); |
158 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv"); | 138 | $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv"); |
159 | like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" ); | ||
160 | } | 139 | } |
161 | 140 | ||
162 | # These checks need a complete command line. An invalid community is used so | 141 | # These checks need a complete command line. An invalid community is used so |
163 | # the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway | 142 | # the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway |
164 | SKIP: { | 143 | SKIP: { |
165 | skip "no non responsive host defined", 2 if ( ! $host_nonresponsive ); | 144 | skip "no non responsive host defined", 2 if ( ! $host_nonresponsive ); |
166 | $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); | 145 | $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c"); |
167 | cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" ); | 146 | cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" ); |
168 | like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); | 147 | # like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); |
169 | } | 148 | } |
170 | 149 | ||
171 | SKIP: { | 150 | SKIP: { |
172 | skip "no non invalid host defined", 2 if ( ! $hostname_invalid ); | 151 | skip "no non invalid host defined", 2 if ( ! $hostname_invalid ); |
173 | $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); | 152 | $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c"); |
174 | cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" ); | 153 | cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" ); |
175 | like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host).*/s', "String matches invalid host"); | 154 | like($res->output, '/.*Unknown host.*/s', "String matches invalid host"); |
176 | } | 155 | } |
diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t index bfe42e16..26d67898 100755 --- a/plugins/tests/check_snmp.t +++ b/plugins/tests/check_snmp.t | |||
@@ -4,12 +4,13 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | use strict; | 6 | use strict; |
7 | use warnings; | ||
7 | use Test::More; | 8 | use Test::More; |
8 | use NPTest; | 9 | use NPTest; |
9 | use FindBin qw($Bin); | 10 | use FindBin qw($Bin); |
10 | use POSIX qw/strftime/; | 11 | use POSIX qw/strftime/; |
11 | 12 | ||
12 | my $tests = 81; | 13 | my $tests = 75; |
13 | # Check that all dependent modules are available | 14 | # Check that all dependent modules are available |
14 | eval { | 15 | eval { |
15 | require NetSNMP::OID; | 16 | require NetSNMP::OID; |
@@ -76,49 +77,36 @@ my $res; | |||
76 | 77 | ||
77 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0"); | 78 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0"); |
78 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" ); | 79 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" ); |
79 | like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); | 80 | like($res->output, '/.*Cisco Internetwork Operating System Software.*/m', "String contains all lines"); |
80 | like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software | | ||
81 | .1.3.6.1.4.1.8072.3.2.67.0: | ||
82 | "Cisco Internetwork Operating System Software | ||
83 | IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version | ||
84 | 12.2(20)EWA, RELEASE SOFTWARE (fc1) | ||
85 | Technical Support: http://www.cisco.com/techsupport | ||
86 | Copyright (c) 1986-2004 by cisco Systems, Inc. | ||
87 | "').'/m', "String contains all lines"); | ||
88 | 81 | ||
89 | # sysContact.0 is "Alice" (from our snmpd.conf) | 82 | # sysContact.0 is "Alice" (from our snmpd.conf) |
90 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1"); | 83 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1"); |
91 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); | 84 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); |
92 | like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); | 85 | # like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); |
93 | like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software ').'"?Alice"?'.quotemeta(' Kisco Outernetwork Oserating Gystem Totware | | 86 | like($res->output, '/.*Cisco Internetwork Operating System Software.*/m', "String contains all lines with multiple OIDs"); |
94 | .1.3.6.1.4.1.8072.3.2.67.0: | 87 | like($res->output, '/.*Alice.*/m', "String contains all lines with multiple OIDs"); |
95 | "Cisco Internetwork Operating System Software | 88 | like($res->output, '/.*Kisco Outernetwork Oserating Gystem Totware.*/m', "String contains all lines with multiple OIDs"); |
96 | IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version | ||
97 | 12.2(20)EWA, RELEASE SOFTWARE (fc1) | ||
98 | Technical Support: http://www.cisco.com/techsupport | ||
99 | Copyright (c) 1986-2004 by cisco Systems, Inc. | ||
100 | " | ||
101 | .1.3.6.1.4.1.8072.3.2.67.1: | ||
102 | "Kisco Outernetwork Oserating Gystem Totware | ||
103 | Copyleft (c) 2400-2689 by kisco Systrems, Inc."').'/m', "String contains all lines with multiple OIDs"); | ||
104 | 89 | ||
105 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2"); | 90 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2"); |
106 | like($res->output, '/'.quotemeta('SNMP OK - This should not confuse check_snmp \"parser\" | | 91 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); |
107 | .1.3.6.1.4.1.8072.3.2.67.2: | 92 | # like($res->output, '/'.quotemeta('This should not confuse check_snmp \"parser\" | |
108 | "This should not confuse check_snmp \"parser\" | 93 | # .1.3.6.1.4.1.8072.3.2.67.2: |
109 | into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1"); | 94 | # "This should not confuse check_snmp \"parser\" |
95 | # into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1"); | ||
110 | 96 | ||
111 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3"); | 97 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3"); |
112 | like($res->output, '/'.quotemeta('SNMP OK - It\'s getting even harder if the line | | 98 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); |
113 | .1.3.6.1.4.1.8072.3.2.67.3: | 99 | # like($res->output, '/'.quotemeta('It\'s getting even harder if the line | |
114 | "It\'s getting even harder if the line | 100 | # .1.3.6.1.4.1.8072.3.2.67.3: |
115 | ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2"); | 101 | # "It\'s getting even harder if the line |
102 | # ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2"); | ||
116 | 103 | ||
117 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4"); | 104 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4"); |
118 | like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C:\\\\\" | | 105 | cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); |
119 | .1.3.6.1.4.1.8072.3.2.67.4: | 106 | # like($res->output, '/'.quotemeta('And now have fun with with this: \"C:\\\\\" | |
120 | "And now have fun with with this: \"C:\\\\\" | 107 | # .1.3.6.1.4.1.8072.3.2.67.4: |
121 | because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); | 108 | # "And now have fun with with this: \"C:\\\\\" |
109 | # because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); | ||
122 | 110 | ||
123 | system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*"); | 111 | system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*"); |
124 | 112 | ||
@@ -131,156 +119,159 @@ SKIP: { | |||
131 | my $ts = time(); | 119 | my $ts = time(); |
132 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); | 120 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); |
133 | is($res->return_code, 0, "Returns OK"); | 121 | is($res->return_code, 0, "Returns OK"); |
134 | is($res->output, "No previous data to calculate rate - assume okay"); | 122 | like($res->output, "/.*No previous data to calculate rate - assume okay.*/"); |
135 | 123 | ||
136 | # test rate 1 second later | 124 | # test rate 1 second later |
137 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); | 125 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); |
138 | is($res->return_code, 1, "WARNING - due to going above rate calculation" ); | 126 | is($res->return_code, 1, "WARNING - due to going above rate calculation" ); |
139 | is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 "); | 127 | like($res->output, "/.*=666.*/"); |
140 | 128 | ||
141 | # test rate with same time | 129 | # test rate with same time |
142 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); | 130 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); |
143 | is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); | 131 | is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); |
144 | is($res->output, "Time duration between plugin calls is invalid"); | 132 | like($res->output, "/.*Time duration between plugin calls is invalid.*/"); |
145 | 133 | ||
146 | 134 | ||
147 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); | 135 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); |
148 | is($res->return_code, 0, "OK for first call" ); | 136 | is($res->return_code, 0, "OK for first call" ); |
149 | is($res->output, "No previous data to calculate rate - assume okay" ); | 137 | like($res->output, "/.*No previous data to calculate rate - assume okay.*/" ); |
150 | 138 | ||
151 | # test rate 1 second later | 139 | # test rate 1 second later |
152 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); | 140 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); |
153 | is($res->return_code, 0, "OK as no thresholds" ); | 141 | is($res->return_code, 0, "OK as no thresholds" ); |
154 | is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label"); | 142 | like($res->output, "/.*inoctets.*=666.*/m", "Check label"); |
155 | 143 | ||
156 | # test rate 3 seconds later | 144 | # test rate 3 seconds later |
157 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); | 145 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); |
158 | is($res->return_code, 0, "OK as no thresholds" ); | 146 | is($res->return_code, 0, "OK as no thresholds" ); |
159 | is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval"); | 147 | like($res->output, "/.*inoctets.*333.*/", "Check rate decreases due to longer interval"); |
160 | 148 | ||
161 | 149 | ||
162 | # label performance data check | 150 | # label performance data check |
163 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" ); | 151 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" ); |
164 | is($res->return_code, 0, "OK as no thresholds" ); | 152 | is($res->return_code, 0, "OK as no thresholds" ); |
165 | is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label"); | 153 | like($res->output, "/.*test.?=67996c/", "Check label"); |
166 | 154 | ||
167 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" ); | 155 | # following test is deactivated since it was not valid due to the guidelines (no single quote in label allowed) |
168 | is($res->return_code, 0, "OK as no thresholds" ); | 156 | # $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" ); |
169 | is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label"); | 157 | # is($res->return_code, 0, "OK as no thresholds" ); |
158 | # is($res->output, "test'test 68662 | \"test'test\"=68662c ", "Check label"); | ||
170 | 159 | ||
171 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" ); | 160 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" ); |
172 | is($res->return_code, 0, "OK as no thresholds" ); | 161 | is($res->return_code, 0, "OK as no thresholds" ); |
173 | is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label"); | 162 | like($res->output, "/.*'test\"test'=68662c.*/", "Check label"); |
174 | 163 | ||
175 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" ); | 164 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" ); |
176 | is($res->return_code, 0, "OK as no thresholds" ); | 165 | is($res->return_code, 0, "OK as no thresholds" ); |
177 | is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label"); | 166 | like($res->output, "/.*.67.10.?=69328c.*/", "Check label"); |
178 | 167 | ||
179 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" ); | 168 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" ); |
180 | is($res->return_code, 0, "OK as no thresholds" ); | 169 | is($res->return_code, 0, "OK as no thresholds" ); |
181 | is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label"); | 170 | like($res->output, "/.*8072.3.2.67.10.?=69994c.*/", "Check label"); |
182 | 171 | ||
183 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" ); | 172 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" ); |
184 | is($res->return_code, 0, "OK as no thresholds" ); | 173 | is($res->return_code, 0, "OK as no thresholds" ); |
185 | is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label"); | 174 | like($res->output, "/.*'test test'=70660c/", "Check label"); |
186 | 175 | ||
187 | 176 | ||
188 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); | 177 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); |
189 | is($res->return_code, 0, "OK for first call" ); | 178 | is($res->return_code, 0, "OK for first call" ); |
190 | is($res->output, "No previous data to calculate rate - assume okay" ); | 179 | like($res->output, "/.*No previous data to calculate rate - assume okay.*/" ); |
191 | 180 | ||
192 | # test 1 second later | 181 | # test 1 second later |
193 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); | 182 | $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); |
194 | is($res->return_code, 0, "OK as no thresholds" ); | 183 | is($res->return_code, 0, "OK as no thresholds" ); |
195 | is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier"); | 184 | like($res->output, "/.*inoctets_per_minute.*=39960/", "Checking multiplier"); |
196 | }; | 185 | }; |
197 | 186 | ||
198 | 187 | ||
199 | 188 | ||
200 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s '\"stringtests\"'" ); | 189 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s 'stringtests'" ); |
201 | is($res->return_code, 0, "OK as string matches" ); | 190 | is($res->return_code, 0, "OK as string matches" ); |
202 | is($res->output, 'SNMP OK - "stringtests" | ', "Good string match" ); | 191 | like($res->output, '/.*stringtests.*/', "Good string match" ); |
203 | 192 | ||
204 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" ); | 193 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" ); |
205 | is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" ); | 194 | is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" ); |
206 | is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Failed string match" ); | 195 | like($res->output, '/.*stringtests.*/', "Failed string match" ); |
207 | 196 | ||
208 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s '\"stringtests\"'" ); | 197 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s 'stringtests'" ); |
209 | is($res->return_code, 2, "CRITICAL as string matches but inverted" ); | 198 | is($res->return_code, 2, "CRITICAL as string matches but inverted" ); |
210 | is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Inverted string match" ); | 199 | like($res->output, '/.*"stringtests".*/', "Inverted string match" ); |
211 | 200 | ||
212 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" ); | 201 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" ); |
213 | is($res->return_code, 0, "OK as string doesn't match but inverted" ); | 202 | is($res->return_code, 0, "OK as string doesn't match but inverted" ); |
214 | is($res->output, 'SNMP OK - "stringtests" | ', "OK as inverted string no match" ); | 203 | like($res->output, '/.*"stringtests".*/', "OK as inverted string no match" ); |
215 | 204 | ||
216 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" ); | 205 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" ); |
217 | is($res->return_code, 1, "Numeric in string test" ); | 206 | # a string is a string and not a number |
218 | is($res->output, 'SNMP WARNING - *3.5* | iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5 ', "WARNING threshold checks for string masquerading as number" ); | 207 | is($res->return_code, 0, "Numeric in string test" ); |
208 | like($res->output, '/.*3.5.*| iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5/', "WARNING threshold checks for string masquerading as number" ); | ||
219 | 209 | ||
220 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" ); | 210 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" ); |
221 | is($res->return_code, 0, "Not really numeric test" ); | 211 | is($res->return_code, 0, "Not really numeric test" ); |
222 | is($res->output, 'SNMP OK - "87.4startswithnumberbutshouldbestring" | ', "Check string with numeric start is still string" ); | 212 | like($res->output, '/.*"87.4startswithnumberbutshouldbestring".*/', "Check string with numeric start is still string" ); |
223 | 213 | ||
224 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" ); | 214 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" ); |
225 | is($res->return_code, 0, "Not really numeric test (trying best to fool it)" ); | 215 | is($res->return_code, 0, "Not really numeric test (trying best to fool it)" ); |
226 | is($res->output, 'SNMP OK - "555\"I said\"" | ', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" ); | 216 | like($res->output, '/.*\'555"I said"\'.*/', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" ); |
227 | 217 | ||
228 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" ); | 218 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" ); |
229 | is($res->return_code, 0, "String check should check whole string, not a parsed number" ); | 219 | is($res->return_code, 0, "String check should check whole string, not a parsed number" ); |
230 | is($res->output, 'SNMP OK - "CUSTOM CHECK OK: foo is 12345" | ', "String check with numbers returns whole string"); | 220 | like($res->output, '/.*CUSTOM CHECK OK: foo is 12345.*/', "String check with numbers returns whole string"); |
231 | 221 | ||
232 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); | 222 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); |
233 | is($res->return_code, 0, "Negative integer check OK" ); | 223 | is($res->return_code, 0, "Negative integer check OK" ); |
234 | is($res->output, 'SNMP OK - -2 | iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3: ', "Negative integer check OK output" ); | 224 | like($res->output, '/.*-2.*| iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3:/', "Negative integer check OK output" ); |
235 | 225 | ||
236 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); | 226 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); |
237 | is($res->return_code, 1, "Negative integer check WARNING" ); | 227 | is($res->return_code, 1, "Negative integer check WARNING" ); |
238 | is($res->output, 'SNMP WARNING - *-3* | iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3: ', "Negative integer check WARNING output" ); | 228 | like($res->output, '/.*-3.*| iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3:/', "Negative integer check WARNING output" ); |
239 | 229 | ||
240 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); | 230 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); |
241 | is($res->return_code, 2, "Negative integer check CRITICAL" ); | 231 | is($res->return_code, 2, "Negative integer check CRITICAL" ); |
242 | is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3: ', "Negative integer check CRITICAL output" ); | 232 | like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3:/', "Negative integer check CRITICAL output" ); |
243 | 233 | ||
244 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" ); | 234 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" ); |
245 | is($res->return_code, 1, "Negative integer as string, WARNING" ); | 235 | is($res->return_code, 1, "Negative integer as string, WARNING" ); |
246 | is($res->output, 'SNMP WARNING - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6: ', "Negative integer as string, WARNING output" ); | 236 | like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6:/', "Negative integer as string, WARNING output" ); |
247 | 237 | ||
248 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" ); | 238 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" ); |
249 | is($res->return_code, 2, "Negative integer as string, CRITICAL" ); | 239 | is($res->return_code, 2, "Negative integer as string, CRITICAL" ); |
250 | is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3: ', "Negative integer as string, CRITICAL output" ); | 240 | like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3:/', "Negative integer as string, CRITICAL output" ); |
251 | 241 | ||
252 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" ); | 242 | # deactivated since the perl agent api of snmpd really does not allow floats |
253 | is($res->return_code, 0, "Negative float OK" ); | 243 | # $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" ); |
254 | is($res->output, 'SNMP OK - -6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" ); | 244 | # is($res->return_code, 0, "Negative float OK" ); |
245 | # is($res->output, '-6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" ); | ||
255 | 246 | ||
256 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" ); | 247 | # $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" ); |
257 | is($res->return_code, 1, "Negative float WARNING" ); | 248 | # is($res->return_code, 1, "Negative float WARNING" ); |
258 | is($res->output, 'SNMP WARNING - *-6.6* | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;@-6.65:~;@-6.55:~ ', "Negative float WARNING output" ); | 249 | # like($res->output, '/-6.6.*| .*67.18=-6.6;@-6.65:~;@-6.55:~/', "Negative float WARNING output" ); |
259 | 250 | ||
260 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" ); | 251 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" ); |
261 | is($res->return_code, 0, "Multiple OIDs with thresholds" ); | 252 | is($res->return_code, 0, "Multiple OIDs with thresholds" ); |
262 | like($res->output, '/SNMP OK - \d+ -4 | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); | 253 | like($res->output, '/-4.*| .*67.10=\d+c;1:100000;2:200000 .*67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); |
263 | 254 | ||
264 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" ); | 255 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" ); |
265 | is($res->return_code, 1, "Multiple OIDs with thresholds" ); | 256 | is($res->return_code, 1, "Multiple OIDs with thresholds" ); |
266 | like($res->output, '/SNMP WARNING - \d+ \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); | 257 | like($res->output, '/-4.*| iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); |
267 | 258 | ||
268 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1" ); | 259 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1 -O" ); |
269 | is($res->return_code, 2, "Multiple OIDs with some thresholds" ); | 260 | is($res->return_code, 2, "Multiple OIDs with some thresholds" ); |
270 | like($res->output, '/SNMP CRITICAL - \*\d+\* \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" ); | 261 | like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" ); |
271 | 262 | ||
272 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19"); | 263 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19"); |
273 | is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" ); | 264 | is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" ); |
274 | is($res->output,'SNMP OK - 42 | iso.3.6.1.4.1.8072.3.2.67.19=42 ', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" ); | 265 | like($res->output,'/.*42.*| iso.3.6.1.4.1.8072.3.2.67.19=42/', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" ); |
275 | 266 | ||
276 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1"); | 267 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1"); |
277 | is($res->return_code, 0, "Test multiply RC" ); | 268 | is($res->return_code, 0, "Test multiply RC" ); |
278 | is($res->output,'SNMP OK - 4.200000 | iso.3.6.1.4.1.8072.3.2.67.19=4.200000 ' , "Test multiply .1 output" ); | 269 | like($res->output,'/.*4.200000.*| iso.3.6.1.4.1.8072.3.2.67.19=4.200000/' , "Test multiply .1 output" ); |
279 | 270 | ||
280 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' "); | 271 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1"); |
281 | is($res->return_code, 0, "Test multiply RC + format" ); | 272 | is($res->return_code, 0, "Test multiply RC" ); |
282 | is($res->output, 'SNMP OK - 4.20 | iso.3.6.1.4.1.8072.3.2.67.19=4.20 ', "Test multiply .1 output + format" ); | 273 | like($res->output, '/.*4.20.*| iso.3.6.1.4.1.8072.3.2.67.19=4.20/', "Test multiply .1 output" ); |
283 | 274 | ||
284 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' -w 1"); | 275 | $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -w 1"); |
285 | is($res->return_code, 1, "Test multiply RC + format + thresholds" ); | 276 | is($res->return_code, 1, "Test multiply RC + thresholds" ); |
286 | is($res->output, 'SNMP WARNING - *4.20* | iso.3.6.1.4.1.8072.3.2.67.19=4.20;1 ', "Test multiply .1 output + format + thresholds" ); | 277 | like($res->output, '/.*4.20.* | iso.3.6.1.4.1.8072.3.2.67.19=4.20+;1/', "Test multiply .1 output + thresholds" ); |
diff --git a/plugins/tests/check_snmp_agent.pl b/plugins/tests/check_snmp_agent.pl index 38912e98..608b6f92 100644 --- a/plugins/tests/check_snmp_agent.pl +++ b/plugins/tests/check_snmp_agent.pl | |||
@@ -4,9 +4,10 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | #use strict; # Doesn't work | 6 | #use strict; # Doesn't work |
7 | use warnings; | ||
7 | use NetSNMP::OID qw(:all); | 8 | use NetSNMP::OID qw(:all); |
8 | use NetSNMP::agent; | 9 | use NetSNMP::agent; |
9 | use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64); | 10 | use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64 ASN_FLOAT); |
10 | #use Math::Int64 qw(uint64); # Skip that module while we don't need it | 11 | #use Math::Int64 qw(uint64); # Skip that module while we don't need it |
11 | sub uint64 { return $_ } | 12 | sub uint64 { return $_ } |
12 | 13 | ||
@@ -22,21 +23,82 @@ IOS (tm) Catalyst 4000 "L3" Switch Software (cat4000-I9K91S-M), Version | |||
22 | Technical Support: http://www.cisco.com/techsupport | 23 | Technical Support: http://www.cisco.com/techsupport |
23 | Copyright (c) 1986-2004 by cisco Systems, Inc. | 24 | Copyright (c) 1986-2004 by cisco Systems, Inc. |
24 | '; | 25 | '; |
25 | my $multilin2 = "Kisco Outernetwork Oserating Gystem Totware | 26 | my $multiline2 = "Kisco Outernetwork Oserating Gystem Totware |
26 | Copyleft (c) 2400-2689 by kisco Systrems, Inc."; | 27 | Copyleft (c) 2400-2689 by kisco Systrems, Inc."; |
27 | my $multilin3 = 'This should not confuse check_snmp "parser" | 28 | my $multiline3 = 'This should not confuse check_snmp "parser" |
28 | into thinking there is no 2nd line'; | 29 | into thinking there is no 2nd line'; |
29 | my $multilin4 = 'It\'s getting even harder if the line | 30 | my $multiline4 = 'It\'s getting even harder if the line |
30 | ends with with this: C:\\'; | 31 | ends with with this: C:\\'; |
31 | my $multilin5 = 'And now have fun with with this: "C:\\" | 32 | my $multiline5 = 'And now have fun with with this: "C:\\" |
32 | because we\'re not done yet!'; | 33 | because we\'re not done yet!'; |
33 | 34 | ||
34 | # Next are arrays of indexes (Type, initial value and increments) | 35 | # Next are arrays of indexes (Type, initial value and increments) |
35 | # 0..19 <---- please update comment when adding/removing fields | 36 | # 0..19 <---- please update comment when adding/removing fields |
36 | my @fields = (ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_UNSIGNED, ASN_UNSIGNED, ASN_COUNTER, ASN_COUNTER64, ASN_UNSIGNED, ASN_COUNTER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER ); | 37 | my @fields = (ASN_OCTET_STR, # 0 |
37 | my @values = ($multiline, $multilin2, $multilin3, $multilin4, $multilin5, 4294965296, 1000, 4294965296, uint64("18446744073709351616"), int(rand(2**32)), 64000, "stringtests", "3.5", "87.4startswithnumberbutshouldbestring", '555"I said"', 'CUSTOM CHECK OK: foo is 12345', -2, '-4', '-6.6', 42 ); | 38 | ASN_OCTET_STR, # 1 |
39 | ASN_OCTET_STR, # 2 | ||
40 | ASN_OCTET_STR, # 3 | ||
41 | ASN_OCTET_STR, # 4 | ||
42 | ASN_UNSIGNED, # 5 | ||
43 | ASN_UNSIGNED, # 6 | ||
44 | ASN_COUNTER, # 7 | ||
45 | ASN_COUNTER64, # 8 | ||
46 | ASN_UNSIGNED, # 9 | ||
47 | ASN_COUNTER, # 10 | ||
48 | ASN_OCTET_STR, # 11 | ||
49 | ASN_OCTET_STR, # 12 | ||
50 | ASN_OCTET_STR, # 13 | ||
51 | ASN_OCTET_STR, # 14 | ||
52 | ASN_OCTET_STR, # 15 | ||
53 | ASN_INTEGER, # 16 | ||
54 | ASN_INTEGER, # 17 | ||
55 | ASN_FLOAT, # 18 | ||
56 | ASN_INTEGER # 19 | ||
57 | ); | ||
58 | my @values = ($multiline, # 0 | ||
59 | $multiline2, # 1 | ||
60 | $multiline3, # 2 | ||
61 | $multiline4, # 3 | ||
62 | $multiline5, # 4 | ||
63 | 4294965296, # 5 | ||
64 | 1000, # 6 | ||
65 | 4294965296, # 7 | ||
66 | uint64("18446744073709351616"), # 8 | ||
67 | int(rand(2**32)), # 9 | ||
68 | 64000, # 10 | ||
69 | "stringtests", # 11 | ||
70 | "3.5", # 12 | ||
71 | "87.4startswithnumberbutshouldbestring", # 13 | ||
72 | '555"I said"', # 14 | ||
73 | 'CUSTOM CHECK OK: foo is 12345', # 15 | ||
74 | '-2', # 16 | ||
75 | '-4', # 17 | ||
76 | '-6.6', # 18 | ||
77 | 42 # 19 | ||
78 | ); | ||
38 | # undef increments are randomized | 79 | # undef increments are randomized |
39 | my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666, undef, undef, undef, undef, undef, -1, undef, undef, 0 ); | 80 | my @incrts = ( |
81 | undef, # 0 | ||
82 | undef, # 1 | ||
83 | undef, # 2 | ||
84 | undef, # 3 | ||
85 | undef, # 4 | ||
86 | 1000, # 5 | ||
87 | -500, # 6 | ||
88 | 1000, # 7 | ||
89 | 100000, # 8 | ||
90 | undef, # 9 | ||
91 | 666, # 10 | ||
92 | undef, # 11 | ||
93 | undef, # 12 | ||
94 | undef, # 13 | ||
95 | undef, # 14 | ||
96 | undef, # 15 | ||
97 | -1, # 16 | ||
98 | 0, # 17 | ||
99 | undef, # 18 | ||
100 | 0 # 19 | ||
101 | ); | ||
40 | 102 | ||
41 | # Number of elements in our OID | 103 | # Number of elements in our OID |
42 | my $oidelts; | 104 | my $oidelts; |
diff --git a/plugins/tests/conf/snmpd.conf b/plugins/tests/conf/snmpd.conf index eff5b0b3..1724c027 100644 --- a/plugins/tests/conf/snmpd.conf +++ b/plugins/tests/conf/snmpd.conf | |||
@@ -19,5 +19,5 @@ syscontact Alice | |||
19 | # Embedded Subagents | 19 | # Embedded Subagents |
20 | ############################################################################### | 20 | ############################################################################### |
21 | 21 | ||
22 | perl do "tests/check_snmp_agent.pl"; | 22 | perl do "./tests/check_snmp_agent.pl"; |
23 | 23 | ||
diff --git a/plugins/tests/test_check_snmp.c b/plugins/tests/test_check_snmp.c new file mode 100644 index 00000000..d71706d0 --- /dev/null +++ b/plugins/tests/test_check_snmp.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 3 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | * | ||
16 | * | ||
17 | *****************************************************************************/ | ||
18 | |||
19 | #include "tap.h" | ||
20 | #include "../../config.h" | ||
21 | |||
22 | #include <unistd.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | |||
26 | #include "utils_base.c" | ||
27 | #include "../check_snmp.d/check_snmp_helpers.h" | ||
28 | |||
29 | char *_np_state_generate_key(int argc, char **argv); | ||
30 | char *_np_state_calculate_location_prefix(void); | ||
31 | |||
32 | int main(int argc, char **argv) { | ||
33 | char *temp_string = (char *)_np_state_generate_key(argc, argv); | ||
34 | ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), | ||
35 | "Got hash with exe and no parameters") || | ||
36 | diag("You are probably running in wrong directory. Must run as ./test_utils"); | ||
37 | |||
38 | int fake_argc = 4; | ||
39 | char *fake_argv[] = { | ||
40 | "./test_utils", | ||
41 | "here", | ||
42 | "--and", | ||
43 | "now", | ||
44 | }; | ||
45 | temp_string = (char *)_np_state_generate_key(fake_argc, fake_argv); | ||
46 | ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), | ||
47 | "Got based on expected argv"); | ||
48 | |||
49 | unsetenv("MP_STATE_PATH"); | ||
50 | temp_string = (char *)_np_state_calculate_location_prefix(); | ||
51 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory"); | ||
52 | |||
53 | setenv("MP_STATE_PATH", "", 1); | ||
54 | temp_string = (char *)_np_state_calculate_location_prefix(); | ||
55 | ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string"); | ||
56 | |||
57 | setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); | ||
58 | temp_string = (char *)_np_state_calculate_location_prefix(); | ||
59 | ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory"); | ||
60 | |||
61 | fake_argc = 1; | ||
62 | fake_argv[0] = "./test_utils"; | ||
63 | state_key temp_state_key1 = np_enable_state(NULL, 51, "check_test", fake_argc, fake_argv); | ||
64 | ok(!strcmp(temp_state_key1.plugin_name, "check_test"), "Got plugin name"); | ||
65 | ok(!strcmp(temp_state_key1.name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), | ||
66 | "Got generated filename"); | ||
67 | |||
68 | state_key temp_state_key2 = | ||
69 | np_enable_state("allowedchars_in_keyname", 77, "check_snmp", fake_argc, fake_argv); | ||
70 | |||
71 | char state_path[1024]; | ||
72 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", | ||
73 | (unsigned long)geteuid()); | ||
74 | ok(!strcmp(temp_state_key2.plugin_name, "check_test"), "Got plugin name"); | ||
75 | ok(!strcmp(temp_state_key2.name, "allowedchars_in_keyname"), "Got key name with valid chars"); | ||
76 | ok(!strcmp(temp_state_key2._filename, state_path), "Got internal filename"); | ||
77 | |||
78 | /* Don't do this test just yet. Will die */ | ||
79 | /* | ||
80 | np_enable_state("bad^chars$in@here", 77); | ||
81 | temp_state_key = this_monitoring_plugin->state; | ||
82 | ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" | ||
83 | ); | ||
84 | */ | ||
85 | |||
86 | state_key temp_state_key3 = | ||
87 | np_enable_state("funnykeyname", 54, "check_snmp", fake_argc, fake_argv); | ||
88 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", | ||
89 | (unsigned long)geteuid()); | ||
90 | ok(!strcmp(temp_state_key3.plugin_name, "check_test"), "Got plugin name"); | ||
91 | ok(!strcmp(temp_state_key3.name, "funnykeyname"), "Got key name"); | ||
92 | |||
93 | ok(!strcmp(temp_state_key3._filename, state_path), "Got internal filename"); | ||
94 | ok(temp_state_key3.data_version == 54, "Version set"); | ||
95 | |||
96 | state_data *temp_state_data = np_state_read(temp_state_key3); | ||
97 | ok(temp_state_data == NULL, "Got no state data as file does not exist"); | ||
98 | |||
99 | /* | ||
100 | temp_fp = fopen("var/statefile", "r"); | ||
101 | if (temp_fp==NULL) | ||
102 | printf("Error opening. errno=%d\n", errno); | ||
103 | printf("temp_fp=%s\n", temp_fp); | ||
104 | ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); | ||
105 | fclose(temp_fp); | ||
106 | */ | ||
107 | |||
108 | temp_state_key3._filename = "var/statefile"; | ||
109 | temp_state_data = np_state_read(temp_state_key3); | ||
110 | ok(temp_state_data != NULL, "Got state data now") || | ||
111 | diag("Are you running in right directory? Will get coredump next if not"); | ||
112 | ok(temp_state_data->time == 1234567890, "Got time"); | ||
113 | ok(!strcmp((char *)temp_state_data->data, "String to read"), "Data as expected"); | ||
114 | |||
115 | temp_state_key3.data_version = 53; | ||
116 | temp_state_data = np_state_read(temp_state_key3); | ||
117 | ok(temp_state_data == NULL, "Older data version gives NULL"); | ||
118 | temp_state_key3.data_version = 54; | ||
119 | |||
120 | temp_state_key3._filename = "var/nonexistent"; | ||
121 | temp_state_data = np_state_read(temp_state_key3); | ||
122 | ok(temp_state_data == NULL, "Missing file gives NULL"); | ||
123 | |||
124 | temp_state_key3._filename = "var/oldformat"; | ||
125 | temp_state_data = np_state_read(temp_state_key3); | ||
126 | ok(temp_state_data == NULL, "Old file format gives NULL"); | ||
127 | |||
128 | temp_state_key3._filename = "var/baddate"; | ||
129 | temp_state_data = np_state_read(temp_state_key3); | ||
130 | ok(temp_state_data == NULL, "Bad date gives NULL"); | ||
131 | |||
132 | temp_state_key3._filename = "var/missingdataline"; | ||
133 | temp_state_data = np_state_read(temp_state_key3); | ||
134 | ok(temp_state_data == NULL, "Missing data line gives NULL"); | ||
135 | |||
136 | unlink("var/generated"); | ||
137 | temp_state_key3._filename = "var/generated"; | ||
138 | |||
139 | time_t current_time = 1234567890; | ||
140 | np_state_write_string(temp_state_key3, current_time, "String to read"); | ||
141 | ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected"); | ||
142 | |||
143 | unlink("var/generated_directory/statefile"); | ||
144 | unlink("var/generated_directory"); | ||
145 | temp_state_key3._filename = "var/generated_directory/statefile"; | ||
146 | current_time = 1234567890; | ||
147 | np_state_write_string(temp_state_key3, current_time, "String to read"); | ||
148 | ok(system("cmp var/generated_directory/statefile var/statefile") == 0, | ||
149 | "Have created directory"); | ||
150 | |||
151 | /* This test to check cannot write to dir - can't automate yet */ | ||
152 | /* | ||
153 | unlink("var/generated_bad_dir"); | ||
154 | mkdir("var/generated_bad_dir", S_IRUSR); | ||
155 | np_state_write_string(current_time, "String to read"); | ||
156 | */ | ||
157 | |||
158 | temp_state_key3._filename = "var/generated"; | ||
159 | time(¤t_time); | ||
160 | np_state_write_string(temp_state_key3, 0, "String to read"); | ||
161 | temp_state_data = np_state_read(temp_state_key3); | ||
162 | /* Check time is set to current_time */ | ||
163 | ok(system("cmp var/generated var/statefile > /dev/null") != 0, | ||
164 | "Generated file should be different this time"); | ||
165 | ok(temp_state_data->time - current_time <= 1, "Has time generated from current time"); | ||
166 | |||
167 | /* Don't know how to automatically test this. Need to be able to redefine die and catch the | ||
168 | * error */ | ||
169 | /* | ||
170 | temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write"; | ||
171 | np_state_write_string(0, "Bad file"); | ||
172 | */ | ||
173 | |||
174 | np_cleanup(); | ||
175 | } | ||
diff --git a/plugins/tests/test_check_snmp.t b/plugins/tests/test_check_snmp.t new file mode 100755 index 00000000..967633e9 --- /dev/null +++ b/plugins/tests/test_check_snmp.t | |||
@@ -0,0 +1,6 @@ | |||
1 | #!/usr/bin/perl | ||
2 | use Test::More; | ||
3 | if (! -e "./test_check_snmp") { | ||
4 | plan skip_all => "./test_check_snmp not compiled - please enable libtap library to test"; | ||
5 | } | ||
6 | exec "./test_check_snmp"; | ||