summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am15
-rw-r--r--plugins/check_apt.c85
-rw-r--r--plugins/check_by_ssh.c34
-rw-r--r--plugins/check_cluster.c10
-rw-r--r--plugins/check_curl.c2696
-rw-r--r--plugins/check_dbi.c15
-rw-r--r--plugins/check_disk.c440
-rw-r--r--plugins/check_dns.c122
-rw-r--r--plugins/check_fping.c40
-rw-r--r--plugins/check_game.c2
-rw-r--r--plugins/check_hpjd.c30
-rw-r--r--plugins/check_http.c430
-rw-r--r--plugins/check_ldap.c7
-rw-r--r--plugins/check_load.c173
-rw-r--r--plugins/check_mysql.c45
-rw-r--r--plugins/check_mysql_query.c12
-rw-r--r--plugins/check_nt.c2
-rw-r--r--plugins/check_ntp.c18
-rw-r--r--plugins/check_ntp_peer.c12
-rw-r--r--plugins/check_ntp_time.c2
-rw-r--r--plugins/check_nwstat.c2
-rw-r--r--plugins/check_pgsql.c80
-rw-r--r--plugins/check_ping.c69
-rw-r--r--plugins/check_procs.c108
-rw-r--r--plugins/check_radius.c8
-rw-r--r--plugins/check_real.c4
-rw-r--r--plugins/check_smtp.c105
-rw-r--r--plugins/check_snmp.c228
-rw-r--r--plugins/check_swap.c306
-rw-r--r--plugins/check_tcp.c25
-rw-r--r--plugins/check_ups.c21
-rw-r--r--plugins/check_users.c37
-rw-r--r--plugins/common.h5
-rw-r--r--plugins/negate.c4
-rw-r--r--plugins/picohttpparser/Makefile.am3
-rw-r--r--plugins/picohttpparser/picohttpparser.c651
-rw-r--r--plugins/picohttpparser/picohttpparser.h87
-rw-r--r--plugins/popen.c89
-rw-r--r--plugins/popen.h1
-rw-r--r--plugins/runcmd.c33
-rw-r--r--plugins/sslutils.c120
-rw-r--r--plugins/t/NPTest.cache.travis62
-rw-r--r--plugins/t/check_by_ssh.t32
-rw-r--r--plugins/t/check_curl.t213
-rw-r--r--plugins/t/check_disk.t46
-rw-r--r--plugins/t/check_dns.t10
-rw-r--r--plugins/t/check_fping.t44
-rw-r--r--plugins/t/check_ftp.t11
-rw-r--r--plugins/t/check_http.t134
-rw-r--r--plugins/t/check_imap.t15
-rw-r--r--plugins/t/check_jabber.t20
-rw-r--r--plugins/t/check_ldap.t17
-rw-r--r--plugins/t/check_load.t15
-rw-r--r--plugins/t/check_mysql.t31
-rw-r--r--plugins/t/check_mysql_query.t13
-rw-r--r--plugins/t/check_nagios.t2
-rw-r--r--plugins/t/check_smtp.t40
-rw-r--r--plugins/t/check_snmp.t84
-rw-r--r--plugins/t/check_ssh.t14
-rw-r--r--plugins/t/check_swap.t6
-rw-r--r--plugins/t/check_tcp.t20
-rw-r--r--plugins/t/check_time.t11
-rw-r--r--plugins/t/negate.t2
-rw-r--r--plugins/tests/certs/.gitignore2
-rw-r--r--plugins/tests/certs/client-cert.pem22
-rw-r--r--plugins/tests/certs/client-key.pem28
-rw-r--r--plugins/tests/certs/clientca-cert.pem25
-rw-r--r--plugins/tests/certs/clientca-key.pem28
-rw-r--r--plugins/tests/certs/clientchain-cert.pem45
-rw-r--r--plugins/tests/certs/clientchain-key.pem28
-rw-r--r--plugins/tests/certs/clientintermediate-cert.pem23
-rw-r--r--plugins/tests/certs/clientintermediate-key.pem28
-rw-r--r--plugins/tests/certs/expired-cert.pem41
-rw-r--r--plugins/tests/certs/expired-key.pem43
-rw-r--r--plugins/tests/certs/ext.cnf2
-rwxr-xr-xplugins/tests/certs/generate-certs.sh63
-rw-r--r--plugins/tests/certs/server-cert.pem41
-rw-r--r--plugins/tests/certs/server-key.pem43
-rwxr-xr-xplugins/tests/check_curl.t526
-rwxr-xr-xplugins/tests/check_http.t361
-rwxr-xr-xplugins/tests/check_procs.t32
-rwxr-xr-xplugins/tests/check_snmp.t151
-rw-r--r--plugins/tests/check_snmp_agent.pl8
-rw-r--r--plugins/tests/var/ps-axwo.debian219
-rw-r--r--plugins/tests/var/ps_axwo.debian84
-rw-r--r--plugins/utils.c161
-rw-r--r--plugins/utils.h20
87 files changed, 7313 insertions, 1729 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 0ddf9bd..49086b7 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -38,7 +38,9 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \
38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
39 check_swap check_fping check_ldap check_game check_dig \ 39 check_swap check_fping check_ldap check_game check_dig \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi 41 check_procs check_mysql_query check_apt check_dbi check_curl
42
43SUBDIRS = picohttpparser
42 44
43EXTRA_DIST = t tests 45EXTRA_DIST = t tests
44 46
@@ -49,10 +51,10 @@ noinst_LIBRARIES = libnpcommon.a
49libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ 51libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \
50 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h 52 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
51 53
52BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a 54BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
53NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) 55NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
54NETLIBS = $(NETOBJS) $(SOCKETLIBS) 56NETLIBS = $(NETOBJS) $(SOCKETLIBS)
55SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) 57SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
56 58
57TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir) 59TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
58 60
@@ -69,6 +71,9 @@ test-debug:
69 71
70check_apt_LDADD = $(BASEOBJS) 72check_apt_LDADD = $(BASEOBJS)
71check_cluster_LDADD = $(BASEOBJS) 73check_cluster_LDADD = $(BASEOBJS)
74check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
75check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
76check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a
72check_dbi_LDADD = $(NETLIBS) $(DBILIBS) 77check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
73check_dig_LDADD = $(NETLIBS) 78check_dig_LDADD = $(NETLIBS)
74check_disk_LDADD = $(BASEOBJS) 79check_disk_LDADD = $(BASEOBJS)
@@ -89,7 +94,7 @@ check_mysql_query_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
89check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE) 94check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
90check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS) 95check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
91check_nagios_LDADD = $(BASEOBJS) 96check_nagios_LDADD = $(BASEOBJS)
92check_nt_LDADD = $(NETLIBS) 97check_nt_LDADD = $(NETLIBS)
93check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 98check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
94check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 99check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
95check_nwstat_LDADD = $(NETLIBS) 100check_nwstat_LDADD = $(NETLIBS)
@@ -107,7 +112,7 @@ check_tcp_LDADD = $(SSLOBJS)
107check_time_LDADD = $(NETLIBS) 112check_time_LDADD = $(NETLIBS)
108check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS) 113check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS)
109check_ups_LDADD = $(NETLIBS) 114check_ups_LDADD = $(NETLIBS)
110check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) 115check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS)
111check_by_ssh_LDADD = $(NETLIBS) 116check_by_ssh_LDADD = $(NETLIBS)
112check_ide_smart_LDADD = $(BASEOBJS) 117check_ide_smart_LDADD = $(BASEOBJS)
113negate_LDADD = $(BASEOBJS) 118negate_LDADD = $(BASEOBJS)
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
index b69680c..fa982ae 100644
--- a/plugins/check_apt.c
+++ b/plugins/check_apt.c
@@ -1,32 +1,32 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_apt plugin 3* Monitoring check_apt plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2006-2008 Monitoring Plugins Development Team 6* Copyright (c) 2006-2008 Monitoring Plugins Development Team
7* 7*
8* Original author: Sean Finney 8* Original author: Sean Finney
9* 9*
10* Description: 10* Description:
11* 11*
12* This file contains the check_apt plugin 12* This file contains the check_apt plugin
13* 13*
14* Check for available updates in apt package management systems 14* Check for available updates in apt package management systems
15* 15*
16* 16*
17* This program is free software: you can redistribute it and/or modify 17* This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by 18* it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or 19* the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20* (at your option) any later version.
21* 21*
22* This program is distributed in the hope that it will be useful, 22* This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23* but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25* GNU General Public License for more details.
26* 26*
27* You should have received a copy of the GNU General Public License 27* You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>. 28* along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29*
30*****************************************************************************/ 30*****************************************************************************/
31 31
32const char *progname = "check_apt"; 32const char *progname = "check_apt";
@@ -76,9 +76,9 @@ int cmpstringp(const void *p1, const void *p2);
76 76
77/* configuration variables */ 77/* configuration variables */
78static int verbose = 0; /* -v */ 78static int verbose = 0; /* -v */
79static int list = 0; /* list packages available for upgrade */ 79static bool list = false; /* list packages available for upgrade */
80static int do_update = 0; /* whether to call apt-get update */ 80static bool do_update = false; /* whether to call apt-get update */
81static int only_critical = 0; /* whether to warn about non-critical updates */ 81static bool only_critical = false; /* whether to warn about non-critical updates */
82static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */ 82static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
83static char *upgrade_opts = NULL; /* options to override defaults for upgrade */ 83static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
84static char *update_opts = NULL; /* options to override defaults for update */ 84static char *update_opts = NULL; /* options to override defaults for update */
@@ -86,6 +86,8 @@ static char *do_include = NULL; /* regexp to only include certain packages */
86static char *do_exclude = NULL; /* regexp to only exclude certain packages */ 86static char *do_exclude = NULL; /* regexp to only exclude certain packages */
87static char *do_critical = NULL; /* regexp specifying critical packages */ 87static char *do_critical = NULL; /* regexp specifying critical packages */
88static char *input_filename = NULL; /* input filename for testing */ 88static char *input_filename = NULL; /* input filename for testing */
89/* number of packages available for upgrade to return WARNING status */
90static int packages_warning = 1;
89 91
90/* other global variables */ 92/* other global variables */
91static int stderr_warning = 0; /* if a cmd issued output on stderr */ 93static int stderr_warning = 0; /* if a cmd issued output on stderr */
@@ -117,7 +119,7 @@ int main (int argc, char **argv) {
117 119
118 if(sec_count > 0){ 120 if(sec_count > 0){
119 result = max_state(result, STATE_CRITICAL); 121 result = max_state(result, STATE_CRITICAL);
120 } else if(packages_available > 0 && only_critical == 0){ 122 } else if(packages_available >= packages_warning && only_critical == false){
121 result = max_state(result, STATE_WARNING); 123 result = max_state(result, STATE_WARNING);
122 } else if(result > STATE_UNKNOWN){ 124 } else if(result > STATE_UNKNOWN){
123 result = STATE_UNKNOWN; 125 result = STATE_UNKNOWN;
@@ -142,7 +144,7 @@ int main (int argc, char **argv) {
142 144
143 for(i = 0; i < sec_count; i++) 145 for(i = 0; i < sec_count; i++)
144 printf("%s (security)\n", secpackages_list[i]); 146 printf("%s (security)\n", secpackages_list[i]);
145 if (only_critical == 0) { 147 if (only_critical == false) {
146 for(i = 0; i < packages_available - sec_count; i++) 148 for(i = 0; i < packages_available - sec_count; i++)
147 printf("%s\n", packages_list[i]); 149 printf("%s\n", packages_list[i]);
148 } 150 }
@@ -164,17 +166,18 @@ int process_arguments (int argc, char **argv) {
164 {"upgrade", optional_argument, 0, 'U'}, 166 {"upgrade", optional_argument, 0, 'U'},
165 {"no-upgrade", no_argument, 0, 'n'}, 167 {"no-upgrade", no_argument, 0, 'n'},
166 {"dist-upgrade", optional_argument, 0, 'd'}, 168 {"dist-upgrade", optional_argument, 0, 'd'},
167 {"list", no_argument, 0, 'l'}, 169 {"list", no_argument, false, 'l'},
168 {"include", required_argument, 0, 'i'}, 170 {"include", required_argument, 0, 'i'},
169 {"exclude", required_argument, 0, 'e'}, 171 {"exclude", required_argument, 0, 'e'},
170 {"critical", required_argument, 0, 'c'}, 172 {"critical", required_argument, 0, 'c'},
171 {"only-critical", no_argument, 0, 'o'}, 173 {"only-critical", no_argument, 0, 'o'},
172 {"input-file", required_argument, 0, INPUT_FILE_OPT}, 174 {"input-file", required_argument, 0, INPUT_FILE_OPT},
175 {"packages-warning", required_argument, 0, 'w'},
173 {0, 0, 0, 0} 176 {0, 0, 0, 0}
174 }; 177 };
175 178
176 while(1) { 179 while(1) {
177 c = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:o", longopts, NULL); 180 c = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL);
178 181
179 if(c == -1 || c == EOF || c == 1) break; 182 if(c == -1 || c == EOF || c == 1) break;
180 183
@@ -209,14 +212,14 @@ int process_arguments (int argc, char **argv) {
209 upgrade=NO_UPGRADE; 212 upgrade=NO_UPGRADE;
210 break; 213 break;
211 case 'u': 214 case 'u':
212 do_update=1; 215 do_update=true;
213 if(optarg!=NULL){ 216 if(optarg!=NULL){
214 update_opts=strdup(optarg); 217 update_opts=strdup(optarg);
215 if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 218 if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed");
216 } 219 }
217 break; 220 break;
218 case 'l': 221 case 'l':
219 list=1; 222 list=true;
220 break; 223 break;
221 case 'i': 224 case 'i':
222 do_include=add_to_regexp(do_include, optarg); 225 do_include=add_to_regexp(do_include, optarg);
@@ -228,11 +231,14 @@ int process_arguments (int argc, char **argv) {
228 do_critical=add_to_regexp(do_critical, optarg); 231 do_critical=add_to_regexp(do_critical, optarg);
229 break; 232 break;
230 case 'o': 233 case 'o':
231 only_critical=1; 234 only_critical=true;
232 break; 235 break;
233 case INPUT_FILE_OPT: 236 case INPUT_FILE_OPT:
234 input_filename = optarg; 237 input_filename = optarg;
235 break; 238 break;
239 case 'w':
240 packages_warning = atoi(optarg);
241 break;
236 default: 242 default:
237 /* print short usage statement if args not parsable */ 243 /* print short usage statement if args not parsable */
238 usage5(); 244 usage5();
@@ -263,7 +269,7 @@ int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkg
263 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 269 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
264 } 270 }
265 } 271 }
266 272
267 if(do_exclude!=NULL){ 273 if(do_exclude!=NULL){
268 regres=regcomp(&ereg, do_exclude, REG_EXTENDED); 274 regres=regcomp(&ereg, do_exclude, REG_EXTENDED);
269 if(regres!=0) { 275 if(regres!=0) {
@@ -272,7 +278,7 @@ int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkg
272 progname, rerrbuf); 278 progname, rerrbuf);
273 } 279 }
274 } 280 }
275 281
276 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE; 282 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE;
277 regres=regcomp(&sreg, crit_ptr, REG_EXTENDED); 283 regres=regcomp(&sreg, crit_ptr, REG_EXTENDED);
278 if(regres!=0) { 284 if(regres!=0) {
@@ -289,7 +295,7 @@ int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkg
289 /* run the upgrade */ 295 /* run the upgrade */
290 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 296 result = np_runcmd(cmdline, &chld_out, &chld_err, 0);
291 } 297 }
292 298
293 /* apt-get upgrade only changes exit status if there is an 299 /* apt-get upgrade only changes exit status if there is an
294 * internal error when run in dry-run mode. therefore we will 300 * internal error when run in dry-run mode. therefore we will
295 * treat such an error as UNKNOWN */ 301 * treat such an error as UNKNOWN */
@@ -365,7 +371,7 @@ int run_update(void){
365 struct output chld_out, chld_err; 371 struct output chld_out, chld_err;
366 char *cmdline; 372 char *cmdline;
367 373
368 /* run the upgrade */ 374 /* run the update */
369 cmdline = construct_cmdline(NO_UPGRADE, update_opts); 375 cmdline = construct_cmdline(NO_UPGRADE, update_opts);
370 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 376 result = np_runcmd(cmdline, &chld_out, &chld_err, 0);
371 /* apt-get update changes exit status if it can't fetch packages. 377 /* apt-get update changes exit status if it can't fetch packages.
@@ -495,16 +501,6 @@ print_help (void)
495 501
496 printf(UT_PLUG_TIMEOUT, timeout_interval); 502 printf(UT_PLUG_TIMEOUT, timeout_interval);
497 503
498 printf (" %s\n", "-U, --upgrade=OPTS");
499 printf (" %s\n", _("[Default] Perform an upgrade. If an optional OPTS argument is provided,"));
500 printf (" %s\n", _("apt-get will be run with these command line options instead of the"));
501 printf (" %s", _("default "));
502 printf ("(%s).\n", UPGRADE_DEFAULT_OPTS);
503 printf (" %s\n", _("Note that you may be required to have root privileges if you do not use"));
504 printf (" %s\n", _("the default options."));
505 printf (" %s\n", "-d, --dist-upgrade=OPTS");
506 printf (" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
507 printf (" %s\n", _("can be provided to override the default options."));
508 printf (" %s\n", "-n, --no-upgrade"); 504 printf (" %s\n", "-n, --no-upgrade");
509 printf (" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least).")); 505 printf (" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least)."));
510 printf (" %s\n", "-l, --list"); 506 printf (" %s\n", "-l, --list");
@@ -524,13 +520,16 @@ print_help (void)
524 printf (" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified")); 520 printf (" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified"));
525 printf (" %s\n", _("multiple times like above. Default is a regexp matching security")); 521 printf (" %s\n", _("multiple times like above. Default is a regexp matching security"));
526 printf (" %s\n", _("upgrades for Debian and Ubuntu:")); 522 printf (" %s\n", _("upgrades for Debian and Ubuntu:"));
527 printf (" \t\%s\n", SECURITY_RE); 523 printf (" \t%s\n", SECURITY_RE);
528 printf (" %s\n", _("Note that the package must first match the include list before its")); 524 printf (" %s\n", _("Note that the package must first match the include list before its"));
529 printf (" %s\n", _("information is compared against the critical list.")); 525 printf (" %s\n", _("information is compared against the critical list."));
530 printf (" %s\n", "-o, --only-critical"); 526 printf (" %s\n", "-o, --only-critical");
531 printf (" %s\n", _("Only warn about upgrades matching the critical list. The total number")); 527 printf (" %s\n", _("Only warn about upgrades matching the critical list. The total number"));
532 printf (" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause")); 528 printf (" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause"));
533 printf (" %s\n\n", _("the plugin to return WARNING status.")); 529 printf (" %s\n", _("the plugin to return WARNING status."));
530 printf (" %s\n", "-w, --packages-warning");
531 printf (" %s\n", _("Minimum number of packages available for upgrade to return WARNING status."));
532 printf (" %s\n\n", _("Default is 1 package."));
534 533
535 printf ("%s\n\n", _("The following options require root privileges and should be used with care:")); 534 printf ("%s\n\n", _("The following options require root privileges and should be used with care:"));
536 printf (" %s\n", "-u, --update=OPTS"); 535 printf (" %s\n", "-u, --update=OPTS");
@@ -538,6 +537,16 @@ print_help (void)
538 printf (" %s\n", _("the default options. Note: you may also need to adjust the global")); 537 printf (" %s\n", _("the default options. Note: you may also need to adjust the global"));
539 printf (" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get")); 538 printf (" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get"));
540 printf (" %s\n", _("upgrade is expected to take longer than the default timeout.")); 539 printf (" %s\n", _("upgrade is expected to take longer than the default timeout."));
540 printf (" %s\n", "-U, --upgrade=OPTS");
541 printf (" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,"));
542 printf (" %s\n", _("apt-get will be run with these command line options instead of the"));
543 printf (" %s", _("default "));
544 printf ("(%s).\n", UPGRADE_DEFAULT_OPTS);
545 printf (" %s\n", _("Note that you may be required to have root privileges if you do not use"));
546 printf (" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade"));
547 printf (" %s\n", "-d, --dist-upgrade=OPTS");
548 printf (" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
549 printf (" %s\n", _("can be provided to override the default options."));
541 550
542 printf(UT_SUPPORT); 551 printf(UT_SUPPORT);
543} 552}
@@ -548,5 +557,5 @@ void
548print_usage(void) 557print_usage(void)
549{ 558{
550 printf ("%s\n", _("Usage:")); 559 printf ("%s\n", _("Usage:"));
551 printf ("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout]\n", progname); 560 printf ("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout] [-w packages-warning]\n", progname);
552} 561}
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 13d8bc3..1ad547e 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -49,6 +49,8 @@ unsigned int commands = 0;
49unsigned int services = 0; 49unsigned int services = 0;
50int skip_stdout = 0; 50int skip_stdout = 0;
51int skip_stderr = 0; 51int skip_stderr = 0;
52int warn_on_stderr = 0;
53bool unknown_timeout = FALSE;
52char *remotecmd = NULL; 54char *remotecmd = NULL;
53char **commargv = NULL; 55char **commargv = NULL;
54int commargc = 0; 56int commargc = 0;
@@ -100,6 +102,13 @@ main (int argc, char **argv)
100 102
101 result = cmd_run_array (commargv, &chld_out, &chld_err, 0); 103 result = cmd_run_array (commargv, &chld_out, &chld_err, 0);
102 104
105 /* SSH returns 255 if connection attempt fails; include the first line of error output */
106 if (result == 255 && unknown_timeout) {
107 printf (_("SSH connection failed: %s\n"),
108 chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
109 return STATE_UNKNOWN;
110 }
111
103 if (verbose) { 112 if (verbose) {
104 for(i = 0; i < chld_out.lines; i++) 113 for(i = 0; i < chld_out.lines; i++)
105 printf("stdout: %s\n", chld_out.line[i]); 114 printf("stdout: %s\n", chld_out.line[i]);
@@ -116,7 +125,10 @@ main (int argc, char **argv)
116 if(chld_err.lines > skip_stderr) { 125 if(chld_err.lines > skip_stderr) {
117 printf (_("Remote command execution failed: %s\n"), 126 printf (_("Remote command execution failed: %s\n"),
118 chld_err.line[skip_stderr]); 127 chld_err.line[skip_stderr]);
119 return max_state_alt(result, STATE_UNKNOWN); 128 if ( warn_on_stderr )
129 return max_state_alt(result, STATE_WARNING);
130 else
131 return max_state_alt(result, STATE_UNKNOWN);
120 } 132 }
121 133
122 /* this is simple if we're not supposed to be passive. 134 /* this is simple if we're not supposed to be passive.
@@ -176,6 +188,7 @@ process_arguments (int argc, char **argv)
176 {"verbose", no_argument, 0, 'v'}, 188 {"verbose", no_argument, 0, 'v'},
177 {"fork", no_argument, 0, 'f'}, 189 {"fork", no_argument, 0, 'f'},
178 {"timeout", required_argument, 0, 't'}, 190 {"timeout", required_argument, 0, 't'},
191 {"unknown-timeout", no_argument, 0, 'U'},
179 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 192 {"host", required_argument, 0, 'H'}, /* backward compatibility */
180 {"hostname", required_argument, 0, 'H'}, 193 {"hostname", required_argument, 0, 'H'},
181 {"port", required_argument,0,'p'}, 194 {"port", required_argument,0,'p'},
@@ -189,6 +202,7 @@ process_arguments (int argc, char **argv)
189 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */ 202 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
190 {"skip-stdout", optional_argument, 0, 'S'}, 203 {"skip-stdout", optional_argument, 0, 'S'},
191 {"skip-stderr", optional_argument, 0, 'E'}, 204 {"skip-stderr", optional_argument, 0, 'E'},
205 {"warn-on-stderr", no_argument, 0, 'W'},
192 {"proto1", no_argument, 0, '1'}, 206 {"proto1", no_argument, 0, '1'},
193 {"proto2", no_argument, 0, '2'}, 207 {"proto2", no_argument, 0, '2'},
194 {"use-ipv4", no_argument, 0, '4'}, 208 {"use-ipv4", no_argument, 0, '4'},
@@ -207,7 +221,7 @@ process_arguments (int argc, char **argv)
207 strcpy (argv[c], "-t"); 221 strcpy (argv[c], "-t");
208 222
209 while (1) { 223 while (1) {
210 c = getopt_long (argc, argv, "Vvh1246fqt:H:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, 224 c = getopt_long (argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts,
211 &option); 225 &option);
212 226
213 if (c == -1 || c == EOF) 227 if (c == -1 || c == EOF)
@@ -229,8 +243,10 @@ process_arguments (int argc, char **argv)
229 else 243 else
230 timeout_interval = atoi (optarg); 244 timeout_interval = atoi (optarg);
231 break; 245 break;
246 case 'U':
247 unknown_timeout = TRUE;
248 break;
232 case 'H': /* host */ 249 case 'H': /* host */
233 host_or_die(optarg);
234 hostname = optarg; 250 hostname = optarg;
235 break; 251 break;
236 case 'p': /* port number */ 252 case 'p': /* port number */
@@ -308,6 +324,9 @@ process_arguments (int argc, char **argv)
308 else 324 else
309 skip_stderr = atoi (optarg); 325 skip_stderr = atoi (optarg);
310 break; 326 break;
327 case 'W': /* exit with warning if there is an output on stderr */
328 warn_on_stderr = 1;
329 break;
311 case 'o': /* Extra options for the ssh command */ 330 case 'o': /* Extra options for the ssh command */
312 comm_append("-o"); 331 comm_append("-o");
313 comm_append(optarg); 332 comm_append(optarg);
@@ -329,7 +348,6 @@ process_arguments (int argc, char **argv)
329 if (c <= argc) { 348 if (c <= argc) {
330 die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname); 349 die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
331 } 350 }
332 host_or_die(argv[c]);
333 hostname = argv[c++]; 351 hostname = argv[c++];
334 } 352 }
335 353
@@ -415,6 +433,8 @@ print_help (void)
415 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]")); 433 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]"));
416 printf (" %s\n", "-E, --skip-stderr[=n]"); 434 printf (" %s\n", "-E, --skip-stderr[=n]");
417 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]")); 435 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]"));
436 printf (" %s\n", "-W, --warn-on-stderr]");
437 printf (" %s\n", _("Exit with an warning, if there is an output on STDERR"));
418 printf (" %s\n", "-f"); 438 printf (" %s\n", "-f");
419 printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed")); 439 printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed"));
420 printf (" %s\n","-C, --command='COMMAND STRING'"); 440 printf (" %s\n","-C, --command='COMMAND STRING'");
@@ -437,6 +457,8 @@ print_help (void)
437 printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]")); 457 printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]"));
438 printf (UT_WARN_CRIT); 458 printf (UT_WARN_CRIT);
439 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 459 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
460 printf (" %s\n","-U, --unknown-timeout");
461 printf (" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
440 printf (UT_VERBOSE); 462 printf (UT_VERBOSE);
441 printf("\n"); 463 printf("\n");
442 printf (" %s\n", _("The most common mode of use is to refer to a local identity file with")); 464 printf (" %s\n", _("The most common mode of use is to refer to a local identity file with"));
@@ -466,8 +488,8 @@ void
466print_usage (void) 488print_usage (void)
467{ 489{
468 printf ("%s\n", _("Usage:")); 490 printf ("%s\n", _("Usage:"));
469 printf (" %s -H <host> -C <command> [-fqv] [-1|-2] [-4|-6]\n" 491 printf (" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
470 " [-S [lines]] [-E [lines]] [-t timeout] [-i identity]\n" 492 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
471 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n" 493 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
472 " [-p port] [-o ssh-option] [-F configfile]\n", 494 " [-p port] [-o ssh-option] [-F configfile]\n",
473 progname); 495 progname);
diff --git a/plugins/check_cluster.c b/plugins/check_cluster.c
index b86e501..e1ede9f 100644
--- a/plugins/check_cluster.c
+++ b/plugins/check_cluster.c
@@ -143,6 +143,7 @@ int main(int argc, char **argv){
143 143
144int process_arguments(int argc, char **argv){ 144int process_arguments(int argc, char **argv){
145 int c; 145 int c;
146 char *ptr;
146 int option=0; 147 int option=0;
147 static struct option longopts[]={ 148 static struct option longopts[]={
148 {"data", required_argument,0,'d'}, 149 {"data", required_argument,0,'d'},
@@ -188,6 +189,15 @@ int process_arguments(int argc, char **argv){
188 189
189 case 'd': /* data values */ 190 case 'd': /* data values */
190 data_vals=(char *)strdup(optarg); 191 data_vals=(char *)strdup(optarg);
192 /* validate data */
193 for (ptr=data_vals;ptr!=NULL;ptr+=2){
194 if (ptr[0]<'0' || ptr[0]>'3')
195 return ERROR;
196 if (ptr[1]=='\0')
197 break;
198 if (ptr[1]!=',')
199 return ERROR;
200 }
191 break; 201 break;
192 202
193 case 'l': /* text label */ 203 case 'l': /* text label */
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
new file mode 100644
index 0000000..d0871c4
--- /dev/null
+++ b/plugins/check_curl.c
@@ -0,0 +1,2696 @@
1/*****************************************************************************
2*
3* Monitoring check_curl plugin
4*
5* License: GPL
6* Copyright (c) 1999-2019 Monitoring Plugins Development Team
7*
8* Description:
9*
10* This file contains the check_curl plugin
11*
12* This plugin tests the HTTP service on the specified host. It can test
13* normal (http) and secure (https) servers, follow redirects, search for
14* strings and regular expressions, check connection times, and report on
15* certificate expiration times.
16*
17* This plugin uses functions from the curl library, see
18* http://curl.haxx.se
19*
20* This program is free software: you can redistribute it and/or modify
21* it under the terms of the GNU General Public License as published by
22* the Free Software Foundation, either version 3 of the License, or
23* (at your option) any later version.
24*
25* This program is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28* GNU General Public License for more details.
29*
30* You should have received a copy of the GNU General Public License
31* along with this program. If not, see <http://www.gnu.org/licenses/>.
32*
33*
34*****************************************************************************/
35const char *progname = "check_curl";
36
37const char *copyright = "2006-2019";
38const char *email = "devel@monitoring-plugins.org";
39
40#include <stdbool.h>
41#include <ctype.h>
42
43#include "common.h"
44#include "utils.h"
45
46#ifndef LIBCURL_PROTOCOL_HTTP
47#error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
48#endif
49
50#include "curl/curl.h"
51#include "curl/easy.h"
52
53#include "picohttpparser.h"
54
55#include "uriparser/Uri.h"
56
57#include <arpa/inet.h>
58#include <netinet/in.h>
59
60#if defined(HAVE_SSL) && defined(USE_OPENSSL)
61#include <openssl/opensslv.h>
62#endif
63
64#include <netdb.h>
65
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
67
68#define DEFAULT_BUFFER_SIZE 2048
69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum {
73 MAX_IPV4_HOSTLENGTH = 255,
74 HTTP_PORT = 80,
75 HTTPS_PORT = 443,
76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15
78};
79
80enum {
81 STICKY_NONE = 0,
82 STICKY_HOST = 1,
83 STICKY_PORT = 2
84};
85
86enum {
87 FOLLOW_HTTP_CURL = 0,
88 FOLLOW_LIBCURL = 1
89};
90
91/* for buffers for header and body */
92typedef struct {
93 char *buf;
94 size_t buflen;
95 size_t bufsize;
96} curlhelp_write_curlbuf;
97
98/* for buffering the data sent in PUT */
99typedef struct {
100 char *buf;
101 size_t buflen;
102 off_t pos;
103} curlhelp_read_curlbuf;
104
105/* for parsing the HTTP status line */
106typedef struct {
107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
108 * never reached the big internet most likely) */
109 int http_minor; /* minor version of the protocol, usually 0 or 1 */
110 int http_code; /* HTTP return code as in RFC 2145 */
111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
112 * http://support.microsoft.com/kb/318380/en-us */
113 const char *msg; /* the human readable message */
114 char *first_line; /* a copy of the first line */
115} curlhelp_statusline;
116
117/* to know the underlying SSL library used by libcurl */
118typedef enum curlhelp_ssl_library {
119 CURLHELP_SSL_LIBRARY_UNKNOWN,
120 CURLHELP_SSL_LIBRARY_OPENSSL,
121 CURLHELP_SSL_LIBRARY_LIBRESSL,
122 CURLHELP_SSL_LIBRARY_GNUTLS,
123 CURLHELP_SSL_LIBRARY_NSS
124} curlhelp_ssl_library;
125
126enum {
127 REGS = 2,
128 MAX_RE_SIZE = 1024
129};
130#include "regex.h"
131regex_t preg;
132regmatch_t pmatch[REGS];
133char regexp[MAX_RE_SIZE];
134int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135int errcode;
136bool invert_regex = false;
137
138char *server_address = NULL;
139char *host_name = NULL;
140char *server_url = 0;
141char server_ip[DEFAULT_BUFFER_SIZE];
142struct curl_slist *server_ips = NULL;
143bool specify_port = false;
144unsigned short server_port = HTTP_PORT;
145unsigned short virtual_port = 0;
146int host_name_length;
147char output_header_search[30] = "";
148char output_string_search[30] = "";
149char *warning_thresholds = NULL;
150char *critical_thresholds = NULL;
151int days_till_exp_warn, days_till_exp_crit;
152thresholds *thlds;
153char user_agent[DEFAULT_BUFFER_SIZE];
154int verbose = 0;
155bool show_extended_perfdata = false;
156bool show_body = false;
157int min_page_len = 0;
158int max_page_len = 0;
159int redir_depth = 0;
160int max_depth = DEFAULT_MAX_REDIRS;
161char *http_method = NULL;
162char *http_post_data = NULL;
163char *http_content_type = NULL;
164CURL *curl;
165bool curl_global_initialized = false;
166bool curl_easy_initialized = false;
167struct curl_slist *header_list = NULL;
168bool body_buf_initialized = false;
169curlhelp_write_curlbuf body_buf;
170bool header_buf_initialized = false;
171curlhelp_write_curlbuf header_buf;
172bool status_line_initialized = false;
173curlhelp_statusline status_line;
174bool put_buf_initialized = false;
175curlhelp_read_curlbuf put_buf;
176char http_header[DEFAULT_BUFFER_SIZE];
177long code;
178long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
179double total_time;
180double time_connect;
181double time_appconnect;
182double time_headers;
183double time_firstbyte;
184char errbuf[MAX_INPUT_BUFFER];
185CURLcode res;
186char url[DEFAULT_BUFFER_SIZE];
187char msg[DEFAULT_BUFFER_SIZE];
188char perfstring[DEFAULT_BUFFER_SIZE];
189char header_expect[MAX_INPUT_BUFFER] = "";
190char string_expect[MAX_INPUT_BUFFER] = "";
191char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
192int server_expect_yn = 0;
193char user_auth[MAX_INPUT_BUFFER] = "";
194char proxy_auth[MAX_INPUT_BUFFER] = "";
195char **http_opt_headers;
196int http_opt_headers_count = 0;
197bool display_html = false;
198int onredirect = STATE_OK;
199int followmethod = FOLLOW_HTTP_CURL;
200int followsticky = STICKY_NONE;
201bool use_ssl = false;
202bool use_sni = true;
203bool check_cert = false;
204bool continue_after_check_cert = false;
205typedef union {
206 struct curl_slist* to_info;
207 struct curl_certinfo* to_certinfo;
208} cert_ptr_union;
209cert_ptr_union cert_ptr;
210int ssl_version = CURL_SSLVERSION_DEFAULT;
211char *client_cert = NULL;
212char *client_privkey = NULL;
213char *ca_cert = NULL;
214bool verify_peer_and_host = false;
215bool is_openssl_callback = false;
216#if defined(HAVE_SSL) && defined(USE_OPENSSL)
217X509 *cert = NULL;
218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
219bool no_body = false;
220int maximum_age = -1;
221int address_family = AF_UNSPEC;
222curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
223int curl_http_version = CURL_HTTP_VERSION_NONE;
224bool automatic_decompression = false;
225char *cookie_jar_file = NULL;
226
227bool process_arguments (int, char**);
228void handle_curl_option_return_code (CURLcode res, const char* option);
229int check_http (void);
230void redir (curlhelp_write_curlbuf*);
231char *perfd_time (double microsec);
232char *perfd_time_connect (double microsec);
233char *perfd_time_ssl (double microsec);
234char *perfd_time_firstbyte (double microsec);
235char *perfd_time_headers (double microsec);
236char *perfd_time_transfer (double microsec);
237char *perfd_size (int page_len);
238void print_help (void);
239void print_usage (void);
240void print_curl_version (void);
241int curlhelp_initwritebuffer (curlhelp_write_curlbuf*);
242int curlhelp_buffer_write_callback (void*, size_t , size_t , void*);
243void curlhelp_freewritebuffer (curlhelp_write_curlbuf*);
244int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t);
245int curlhelp_buffer_read_callback (void *, size_t , size_t , void *);
246void curlhelp_freereadbuffer (curlhelp_read_curlbuf *);
247curlhelp_ssl_library curlhelp_get_ssl_library ();
248const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library);
249int net_noopenssl_check_certificate (cert_ptr_union*, int, int);
250
251int curlhelp_parse_statusline (const char*, curlhelp_statusline *);
252void curlhelp_free_statusline (curlhelp_statusline *);
253char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header);
254int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]);
255int get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf);
256
257#if defined(HAVE_SSL) && defined(USE_OPENSSL)
258int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit);
259#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
260
261void remove_newlines (char *);
262void test_file (char *);
263
264int
265main (int argc, char **argv)
266{
267 int result = STATE_UNKNOWN;
268
269 setlocale (LC_ALL, "");
270 bindtextdomain (PACKAGE, LOCALEDIR);
271 textdomain (PACKAGE);
272
273 /* Parse extra opts if any */
274 argv = np_extra_opts (&argc, argv, progname);
275
276 /* set defaults */
277 snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
278 progname, NP_VERSION, VERSION, curl_version());
279
280 /* parse arguments */
281 if (process_arguments (argc, argv) == false)
282 usage4 (_("Could not parse arguments"));
283
284 if (display_html)
285 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
286 use_ssl ? "https" : "http",
287 host_name ? host_name : server_address,
288 virtual_port ? virtual_port : server_port,
289 server_url);
290
291 result = check_http ();
292 return result;
293}
294
295#ifdef HAVE_SSL
296#ifdef USE_OPENSSL
297
298int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
299{
300 (void) preverify_ok;
301 /* TODO: we get all certificates of the chain, so which ones
302 * should we test?
303 * TODO: is the last certificate always the server certificate?
304 */
305 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
306#if OPENSSL_VERSION_NUMBER >= 0x10100000L
307 X509_up_ref(cert);
308#endif
309 if (verbose>=2) {
310 puts("* SSL verify callback with certificate:");
311 X509_NAME *subject, *issuer;
312 printf("* issuer:\n");
313 issuer = X509_get_issuer_name( cert );
314 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
315 printf("* curl verify_callback:\n* subject:\n");
316 subject = X509_get_subject_name( cert );
317 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
318 puts("");
319 }
320 return 1;
321}
322
323CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm)
324{
325 (void) curl; // ignore unused parameter
326 (void) parm; // ignore unused parameter
327 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
328
329 return CURLE_OK;
330}
331
332#endif /* USE_OPENSSL */
333#endif /* HAVE_SSL */
334
335/* returns a string "HTTP/1.x" or "HTTP/2" */
336static char *string_statuscode (int major, int minor)
337{
338 static char buf[10];
339
340 switch (major) {
341 case 1:
342 snprintf (buf, sizeof (buf), "HTTP/%d.%d", major, minor);
343 break;
344 case 2:
345 case 3:
346 snprintf (buf, sizeof (buf), "HTTP/%d", major);
347 break;
348 default:
349 /* assuming here HTTP/N with N>=4 */
350 snprintf (buf, sizeof (buf), "HTTP/%d", major);
351 break;
352 }
353
354 return buf;
355}
356
357/* Checks if the server 'reply' is one of the expected 'statuscodes' */
358static int
359expected_statuscode (const char *reply, const char *statuscodes)
360{
361 char *expected, *code;
362 int result = 0;
363
364 if ((expected = strdup (statuscodes)) == NULL)
365 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
366
367 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
368 if (strstr (reply, code) != NULL) {
369 result = 1;
370 break;
371 }
372
373 free (expected);
374 return result;
375}
376
377void
378handle_curl_option_return_code (CURLcode res, const char* option)
379{
380 if (res != CURLE_OK) {
381 snprintf (msg,
382 DEFAULT_BUFFER_SIZE,
383 _("Error while setting cURL option '%s': cURL returned %d - %s"),
384 option,
385 res,
386 curl_easy_strerror(res));
387 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
388 }
389}
390
391int
392lookup_host (const char *host, char *buf, size_t buflen)
393{
394 struct addrinfo hints, *res, *result;
395 char addrstr[100];
396 size_t addrstr_len;
397 int errcode;
398 void *ptr;
399 size_t buflen_remaining = buflen - 1;
400
401 memset (&hints, 0, sizeof (hints));
402 hints.ai_family = address_family;
403 hints.ai_socktype = SOCK_STREAM;
404 hints.ai_flags |= AI_CANONNAME;
405
406 errcode = getaddrinfo (host, NULL, &hints, &result);
407 if (errcode != 0)
408 return errcode;
409
410 strcpy(buf, "");
411 res = result;
412
413 while (res) {
414 switch (res->ai_family) {
415 case AF_INET:
416 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
417 break;
418 case AF_INET6:
419 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
420 break;
421 }
422
423 inet_ntop (res->ai_family, ptr, addrstr, 100);
424 if (verbose >= 1) {
425 printf ("* getaddrinfo IPv%d address: %s\n",
426 res->ai_family == PF_INET6 ? 6 : 4, addrstr);
427 }
428
429 // Append all IPs to buf as a comma-separated string
430 addrstr_len = strlen(addrstr);
431 if (buflen_remaining > addrstr_len + 1) {
432 if (buf[0] != '\0') {
433 strncat(buf, ",", buflen_remaining);
434 buflen_remaining -= 1;
435 }
436 strncat(buf, addrstr, buflen_remaining);
437 buflen_remaining -= addrstr_len;
438 }
439
440 res = res->ai_next;
441 }
442
443 freeaddrinfo(result);
444
445 return 0;
446}
447
448static void
449cleanup (void)
450{
451 if (status_line_initialized) curlhelp_free_statusline(&status_line);
452 status_line_initialized = false;
453 if (curl_easy_initialized) curl_easy_cleanup (curl);
454 curl_easy_initialized = false;
455 if (curl_global_initialized) curl_global_cleanup ();
456 curl_global_initialized = false;
457 if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf);
458 body_buf_initialized = false;
459 if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf);
460 header_buf_initialized = false;
461 if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf);
462 put_buf_initialized = false;
463}
464
465int
466check_http (void)
467{
468 int result = STATE_OK;
469 int page_len = 0;
470 int i;
471 char *force_host_header = NULL;
472 struct curl_slist *host = NULL;
473 char addrstr[DEFAULT_BUFFER_SIZE/2];
474 char dnscache[DEFAULT_BUFFER_SIZE];
475
476 /* initialize curl */
477 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK)
478 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
479 curl_global_initialized = true;
480
481 if ((curl = curl_easy_init()) == NULL) {
482 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
483 }
484 curl_easy_initialized = true;
485
486 /* register cleanup function to shut down libcurl properly */
487 atexit (cleanup);
488
489 if (verbose >= 1)
490 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
491
492 /* print everything on stdout like check_http would do */
493 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
494
495 if (automatic_decompression)
496#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
497 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
498#else
499 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
500#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
501
502 /* initialize buffer for body of the answer */
503 if (curlhelp_initwritebuffer(&body_buf) < 0)
504 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
505 body_buf_initialized = true;
506 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION");
507 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
508
509 /* initialize buffer for header of the answer */
510 if (curlhelp_initwritebuffer( &header_buf ) < 0)
511 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" );
512 header_buf_initialized = true;
513 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION");
514 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
515
516 /* set the error buffer */
517 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
518
519 /* set timeouts */
520 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
521 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
522
523 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy
524 if(use_ssl && host_name != NULL) {
525 if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) {
526 snprintf (msg,
527 DEFAULT_BUFFER_SIZE,
528 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
529 server_address,
530 res,
531 gai_strerror (res));
532 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
533 }
534 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
535 host = curl_slist_append(NULL, dnscache);
536 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
537 if (verbose>=1)
538 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache);
539 }
540
541 // If server_address is an IPv6 address it must be surround by square brackets
542 struct in6_addr tmp_in_addr;
543 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
544 char *new_server_address = malloc(strlen(server_address) + 3);
545 if (new_server_address == NULL) {
546 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
547 }
548 snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address);
549 free(server_address);
550 server_address = new_server_address;
551 }
552
553 /* compose URL: use the address we want to connect to, set Host: header later */
554 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s",
555 use_ssl ? "https" : "http",
556 ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address,
557 server_port,
558 server_url
559 );
560
561 if (verbose>=1)
562 printf ("* curl CURLOPT_URL: %s\n", url);
563 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, url), "CURLOPT_URL");
564
565 /* extract proxy information for legacy proxy https requests */
566 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
567 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
568 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
569 if (verbose>=2)
570 printf ("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
571 http_method = "GET";
572 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, server_url), "CURLOPT_URL");
573 }
574
575 /* disable body for HEAD request */
576 if (http_method && !strcmp (http_method, "HEAD" )) {
577 no_body = true;
578 }
579
580 /* set HTTP protocol version */
581 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION");
582
583 /* set HTTP method */
584 if (http_method) {
585 if (!strcmp(http_method, "POST"))
586 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POST, 1), "CURLOPT_POST");
587 else if (!strcmp(http_method, "PUT"))
588 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
589 else
590 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
591 }
592
593 /* check if Host header is explicitly set in options */
594 if (http_opt_headers_count) {
595 for (i = 0; i < http_opt_headers_count ; i++) {
596 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
597 force_host_header = http_opt_headers[i];
598 }
599 }
600 }
601
602 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
603 if(host_name != NULL && force_host_header == NULL) {
604 if((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
605 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
606 } else {
607 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
608 }
609 header_list = curl_slist_append (header_list, http_header);
610 }
611
612 /* always close connection, be nice to servers */
613 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
614 header_list = curl_slist_append (header_list, http_header);
615
616 /* attach additional headers supplied by the user */
617 /* optionally send any other header tag */
618 if (http_opt_headers_count) {
619 for (i = 0; i < http_opt_headers_count ; i++) {
620 header_list = curl_slist_append (header_list, http_opt_headers[i]);
621 }
622 /* This cannot be free'd here because a redirection will then try to access this and segfault */
623 /* Covered in a testcase in tests/check_http.t */
624 /* free(http_opt_headers); */
625 }
626
627 /* set HTTP headers */
628 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER");
629
630#ifdef LIBCURL_FEATURE_SSL
631
632 /* set SSL version, warn about insecure or unsupported versions */
633 if (use_ssl) {
634 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
635 }
636
637 /* client certificate and key to present to server (SSL) */
638 if (client_cert)
639 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
640 if (client_privkey)
641 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
642 if (ca_cert) {
643 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
644 }
645 if (ca_cert || verify_peer_and_host) {
646 /* per default if we have a CA verify both the peer and the
647 * hostname in the certificate, can be switched off later */
648 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
649 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
650 } else {
651 /* backward-compatible behaviour, be tolerant in checks
652 * TODO: depending on more options have aspects we want
653 * to be less tolerant about ssl verfications
654 */
655 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
656 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
657 }
658
659 /* detect SSL library used by libcurl */
660 ssl_library = curlhelp_get_ssl_library ();
661
662 /* try hard to get a stack of certificates to verify against */
663 if (check_cert) {
664#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
665 /* inform curl to report back certificates */
666 switch (ssl_library) {
667 case CURLHELP_SSL_LIBRARY_OPENSSL:
668 case CURLHELP_SSL_LIBRARY_LIBRESSL:
669 /* set callback to extract certificate with OpenSSL context function (works with
670 * OpenSSL-style libraries only!) */
671#ifdef USE_OPENSSL
672 /* libcurl and monitoring plugins built with OpenSSL, good */
673 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
674 is_openssl_callback = true;
675#else /* USE_OPENSSL */
676#endif /* USE_OPENSSL */
677 /* libcurl is built with OpenSSL, monitoring plugins, so falling
678 * back to manually extracting certificate information */
679 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
680 break;
681
682 case CURLHELP_SSL_LIBRARY_NSS:
683#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
684 /* NSS: support for CERTINFO is implemented since 7.34.0 */
685 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
686#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
687 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library));
688#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
689 break;
690
691 case CURLHELP_SSL_LIBRARY_GNUTLS:
692#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
693 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
694 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
695#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
696 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library));
697#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
698 break;
699
700 case CURLHELP_SSL_LIBRARY_UNKNOWN:
701 default:
702 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library));
703 break;
704 }
705#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
706 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
707 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
708 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
709 else
710 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl too old and has no CURLOPT_CERTINFO)\n");
711#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
712 }
713
714#endif /* LIBCURL_FEATURE_SSL */
715
716 /* set default or user-given user agent identification */
717 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
718
719 /* proxy-authentication */
720 if (strcmp(proxy_auth, ""))
721 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
722
723 /* authentication */
724 if (strcmp(user_auth, ""))
725 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
726
727 /* TODO: parameter auth method, bitfield of following methods:
728 * CURLAUTH_BASIC (default)
729 * CURLAUTH_DIGEST
730 * CURLAUTH_DIGEST_IE
731 * CURLAUTH_NEGOTIATE
732 * CURLAUTH_NTLM
733 * CURLAUTH_NTLM_WB
734 *
735 * convenience tokens for typical sets of methods:
736 * CURLAUTH_ANYSAFE: most secure, without BASIC
737 * or CURLAUTH_ANY: most secure, even BASIC if necessary
738 *
739 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
740 */
741
742 /* handle redirections */
743 if (onredirect == STATE_DEPENDENT) {
744 if( followmethod == FOLLOW_LIBCURL ) {
745 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
746
747 /* default -1 is infinite, not good, could lead to zombie plugins!
748 Setting it to one bigger than maximal limit to handle errors nicely below
749 */
750 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS");
751
752 /* for now allow only http and https (we are a http(s) check plugin in the end) */
753#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
754 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR");
755#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
756 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS");
757#endif
758
759 /* TODO: handle the following aspects of redirection, make them
760 * command line options too later:
761 CURLOPT_POSTREDIR: method switch
762 CURLINFO_REDIRECT_URL: custom redirect option
763 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
764 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size?
765 */
766 } else {
767 /* old style redirection is handled below */
768 }
769 }
770
771 /* no-body */
772 if (no_body)
773 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
774
775 /* IPv4 or IPv6 forced DNS resolution */
776 if (address_family == AF_UNSPEC)
777 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
778 else if (address_family == AF_INET)
779 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
780#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6)
781 else if (address_family == AF_INET6)
782 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
783#endif
784
785 /* either send http POST data (any data, not only POST)*/
786 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) {
787 /* set content of payload for POST and PUT */
788 if (http_content_type) {
789 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type);
790 header_list = curl_slist_append (header_list, http_header);
791 }
792 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
793 * in case of no POST/PUT data */
794 if (!http_post_data)
795 http_post_data = "";
796 if (!strcmp(http_method, "POST")) {
797 /* POST method, set payload with CURLOPT_POSTFIELDS */
798 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS");
799 } else if (!strcmp(http_method, "PUT")) {
800 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION");
801 if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0)
802 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
803 put_buf_initialized = true;
804 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
805 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE");
806 }
807 }
808
809 /* cookie handling */
810 if (cookie_jar_file != NULL) {
811 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
812 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
813 }
814
815 /* do the request */
816 res = curl_easy_perform(curl);
817
818 if (verbose>=2 && http_post_data)
819 printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data);
820
821 /* free header and server IP resolve lists, we don't need it anymore */
822 curl_slist_free_all (header_list); header_list = NULL;
823 curl_slist_free_all (server_ips); server_ips = NULL;
824 if (host) {
825 curl_slist_free_all (host); host = NULL;
826 }
827
828 /* Curl errors, result in critical Nagios state */
829 if (res != CURLE_OK) {
830 snprintf (msg,
831 DEFAULT_BUFFER_SIZE,
832 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"),
833 server_port,
834 res,
835 errbuf[0] ? errbuf : curl_easy_strerror(res));
836 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
837 }
838
839 /* certificate checks */
840#ifdef LIBCURL_FEATURE_SSL
841 if (use_ssl) {
842 if (check_cert) {
843 if (is_openssl_callback) {
844#ifdef USE_OPENSSL
845 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
846 * and we actually have OpenSSL in the monitoring tools
847 */
848 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
849 if (!continue_after_check_cert) {
850 return result;
851 }
852#else /* USE_OPENSSL */
853 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
854#endif /* USE_OPENSSL */
855 } else {
856 int i;
857 struct curl_slist *slist;
858
859 cert_ptr.to_info = NULL;
860 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
861 if (!res && cert_ptr.to_info) {
862#ifdef USE_OPENSSL
863 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
864 * We only check the first certificate and assume it's the one of the server
865 */
866 const char* raw_cert = NULL;
867 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
868 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
869 if (verbose >= 2)
870 printf ("%d ** %s\n", i, slist->data);
871 if (strncmp (slist->data, "Cert:", 5) == 0) {
872 raw_cert = &slist->data[5];
873 goto GOT_FIRST_CERT;
874 }
875 }
876 }
877GOT_FIRST_CERT:
878 if (!raw_cert) {
879 snprintf (msg,
880 DEFAULT_BUFFER_SIZE,
881 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
882 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
883 }
884 BIO* cert_BIO = BIO_new (BIO_s_mem());
885 BIO_write (cert_BIO, raw_cert, strlen(raw_cert));
886 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL);
887 if (!cert) {
888 snprintf (msg,
889 DEFAULT_BUFFER_SIZE,
890 _("Cannot read certificate from CERTINFO information - BIO error"));
891 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
892 }
893 BIO_free (cert_BIO);
894 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
895 if (!continue_after_check_cert) {
896 return result;
897 }
898#else /* USE_OPENSSL */
899 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
900 * so we use the libcurl CURLINFO data
901 */
902 result = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
903 if (!continue_after_check_cert) {
904 return result;
905 }
906#endif /* USE_OPENSSL */
907 } else {
908 snprintf (msg,
909 DEFAULT_BUFFER_SIZE,
910 _("Cannot retrieve certificates - cURL returned %d - %s"),
911 res,
912 curl_easy_strerror(res));
913 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
914 }
915 }
916 }
917 }
918#endif /* LIBCURL_FEATURE_SSL */
919
920 /* we got the data and we executed the request in a given time, so we can append
921 * performance data to the answer always
922 */
923 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME");
924 page_len = get_content_length(&header_buf, &body_buf);
925 if(show_extended_perfdata) {
926 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
927 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
928 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
929 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), "CURLINFO_STARTTRANSFER_TIME");
930 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s",
931 perfd_time(total_time),
932 perfd_size(page_len),
933 perfd_time_connect(time_connect),
934 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "",
935 perfd_time_headers(time_headers - time_appconnect),
936 perfd_time_firstbyte(time_firstbyte - time_headers),
937 perfd_time_transfer(total_time-time_firstbyte)
938 );
939 } else {
940 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
941 perfd_time(total_time),
942 perfd_size(page_len)
943 );
944 }
945
946 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
948 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
949
950 /* get status line of answer, check sanity of HTTP code */
951 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
952 snprintf (msg,
953 DEFAULT_BUFFER_SIZE,
954 "Unparsable status line in %.3g seconds response time|%s\n",
955 total_time,
956 perfstring);
957 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
958 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
959 }
960 status_line_initialized = true;
961
962 /* get result code from cURL */
963 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
964 if (verbose>=2)
965 printf ("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
966
967 /* print status line, header, body if verbose */
968 if (verbose >= 2) {
969 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf,
970 (no_body ? " [[ skipped ]]" : body_buf.buf));
971 }
972
973 /* make sure the status line matches the response we are looking for */
974 if (!expected_statuscode(status_line.first_line, server_expect)) {
975 if (server_port == HTTP_PORT)
976 snprintf(msg,
977 DEFAULT_BUFFER_SIZE,
978 _("Invalid HTTP response received from host: %s\n"),
979 status_line.first_line);
980 else
981 snprintf(msg,
982 DEFAULT_BUFFER_SIZE,
983 _("Invalid HTTP response received from host on port %d: %s\n"),
984 server_port,
985 status_line.first_line);
986 die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg,
987 show_body ? "\n" : "",
988 show_body ? body_buf.buf : "");
989 }
990
991 if( server_expect_yn ) {
992 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
993 if (verbose)
994 printf ("%s\n",msg);
995 result = STATE_OK;
996 }
997 else {
998 /* illegal return codes result in a critical state */
999 if (code >= 600 || code < 100) {
1000 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
1001 /* server errors result in a critical state */
1002 } else if (code >= 500) {
1003 result = STATE_CRITICAL;
1004 /* client errors result in a warning state */
1005 } else if (code >= 400) {
1006 result = STATE_WARNING;
1007 /* check redirected page if specified */
1008 } else if (code >= 300) {
1009 if (onredirect == STATE_DEPENDENT) {
1010 if( followmethod == FOLLOW_LIBCURL ) {
1011 code = status_line.http_code;
1012 } else {
1013 /* old check_http style redirection, if we come
1014 * back here, we are in the same status as with
1015 * the libcurl method
1016 */
1017 redir (&header_buf);
1018 }
1019 } else {
1020 /* this is a specific code in the command line to
1021 * be returned when a redirection is encountered
1022 */
1023 }
1024 result = max_state_alt (onredirect, result);
1025 /* all other codes are considered ok */
1026 } else {
1027 result = STATE_OK;
1028 }
1029 }
1030
1031 /* libcurl redirection internally, handle error states here */
1032 if( followmethod == FOLLOW_LIBCURL ) {
1033 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1034 if (verbose >= 2)
1035 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1036 if (redir_depth > max_depth) {
1037 snprintf (msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl",
1038 max_depth);
1039 die (STATE_WARNING, "HTTP WARNING - %s", msg);
1040 }
1041 }
1042
1043 /* check status codes, set exit status accordingly */
1044 if( status_line.http_code != code ) {
1045 die (STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1046 string_statuscode (status_line.http_major, status_line.http_minor),
1047 status_line.http_code, status_line.msg, code);
1048 }
1049
1050 if (maximum_age >= 0) {
1051 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1052 }
1053
1054 /* Page and Header content checks go here */
1055
1056 if (strlen (header_expect)) {
1057 if (!strstr (header_buf.buf, header_expect)) {
1058
1059 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search));
1060
1061 if(output_header_search[sizeof(output_header_search)-1]!='\0') {
1062 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4);
1063 }
1064
1065 char tmp[DEFAULT_BUFFER_SIZE];
1066
1067 snprintf (tmp,
1068 DEFAULT_BUFFER_SIZE,
1069 _("%sheader '%s' not found on '%s://%s:%d%s', "),
1070 msg,
1071 output_header_search,
1072 use_ssl ? "https" : "http",
1073 host_name ? host_name : server_address,
1074 server_port,
1075 server_url);
1076
1077 strcpy(msg, tmp);
1078
1079 result = STATE_CRITICAL;
1080 }
1081 }
1082
1083 if (strlen (string_expect)) {
1084 if (!strstr (body_buf.buf, string_expect)) {
1085
1086 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search));
1087
1088 if(output_string_search[sizeof(output_string_search)-1]!='\0') {
1089 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4);
1090 }
1091
1092 char tmp[DEFAULT_BUFFER_SIZE];
1093
1094 snprintf (tmp,
1095 DEFAULT_BUFFER_SIZE,
1096 _("%sstring '%s' not found on '%s://%s:%d%s', "),
1097 msg,
1098 output_string_search,
1099 use_ssl ? "https" : "http",
1100 host_name ? host_name : server_address,
1101 server_port,
1102 server_url);
1103
1104 strcpy(msg, tmp);
1105
1106 result = STATE_CRITICAL;
1107 }
1108 }
1109
1110 if (strlen (regexp)) {
1111 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0);
1112 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
1113 /* OK - No-op to avoid changing the logic around it */
1114 result = max_state_alt(STATE_OK, result);
1115 }
1116 else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1117 if (!invert_regex) {
1118 char tmp[DEFAULT_BUFFER_SIZE];
1119
1120 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
1121 strcpy(msg, tmp);
1122
1123 } else {
1124 char tmp[DEFAULT_BUFFER_SIZE];
1125
1126 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1127 strcpy(msg, tmp);
1128
1129 }
1130 result = STATE_CRITICAL;
1131 } else {
1132 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1133
1134 char tmp[DEFAULT_BUFFER_SIZE];
1135
1136 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
1137 strcpy(msg, tmp);
1138 result = STATE_UNKNOWN;
1139 }
1140 }
1141
1142 /* make sure the page is of an appropriate size */
1143 if ((max_page_len > 0) && (page_len > max_page_len)) {
1144 char tmp[DEFAULT_BUFFER_SIZE];
1145
1146 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
1147
1148 strcpy(msg, tmp);
1149
1150 result = max_state_alt(STATE_WARNING, result);
1151
1152 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1153 char tmp[DEFAULT_BUFFER_SIZE];
1154
1155 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
1156 strcpy(msg, tmp);
1157 result = max_state_alt(STATE_WARNING, result);
1158 }
1159
1160 /* -w, -c: check warning and critical level */
1161 result = max_state_alt(get_status(total_time, thlds), result);
1162
1163 /* Cut-off trailing characters */
1164 if (strlen(msg) >= 2) {
1165 if(msg[strlen(msg)-2] == ',')
1166 msg[strlen(msg)-2] = '\0';
1167 else
1168 msg[strlen(msg)-3] = '\0';
1169 }
1170
1171 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
1172 die (result, "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s",
1173 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor),
1174 status_line.http_code, status_line.msg,
1175 strlen(msg) > 0 ? " - " : "",
1176 msg, page_len, total_time,
1177 (display_html ? "</A>" : ""),
1178 perfstring,
1179 (show_body ? body_buf.buf : ""),
1180 (show_body ? "\n" : "") );
1181
1182 return result;
1183}
1184
1185int
1186uri_strcmp (const UriTextRangeA range, const char* s)
1187{
1188 if (!range.first) return -1;
1189 if (range.afterLast - range.first < strlen (s)) return -1;
1190 return strncmp (s, range.first, min( range.afterLast - range.first, strlen (s)));
1191}
1192
1193char*
1194uri_string (const UriTextRangeA range, char* buf, size_t buflen)
1195{
1196 if (!range.first) return "(null)";
1197 strncpy (buf, range.first, max (buflen-1, range.afterLast - range.first));
1198 buf[max (buflen-1, range.afterLast - range.first)] = '\0';
1199 buf[range.afterLast - range.first] = '\0';
1200 return buf;
1201}
1202
1203void
1204redir (curlhelp_write_curlbuf* header_buf)
1205{
1206 char *location = NULL;
1207 curlhelp_statusline status_line;
1208 struct phr_header headers[255];
1209 size_t nof_headers = 255;
1210 size_t msglen;
1211 char buf[DEFAULT_BUFFER_SIZE];
1212 char ipstr[INET_ADDR_MAX_SIZE];
1213 int new_port;
1214 char *new_host;
1215 char *new_url;
1216
1217 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
1218 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
1219 headers, &nof_headers, 0);
1220
1221 location = get_header_value (headers, nof_headers, "location");
1222
1223 if (verbose >= 2)
1224 printf(_("* Seen redirect location %s\n"), location);
1225
1226 if (++redir_depth > max_depth)
1227 die (STATE_WARNING,
1228 _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"),
1229 max_depth, location, (display_html ? "</A>" : ""));
1230
1231 UriParserStateA state;
1232 UriUriA uri;
1233 state.uri = &uri;
1234 if (uriParseUriA (&state, location) != URI_SUCCESS) {
1235 if (state.errorCode == URI_ERROR_SYNTAX) {
1236 die (STATE_UNKNOWN,
1237 _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"),
1238 location, (display_html ? "</A>" : ""));
1239 } else if (state.errorCode == URI_ERROR_MALLOC) {
1240 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1241 }
1242 }
1243
1244 if (verbose >= 2) {
1245 printf (_("** scheme: %s\n"),
1246 uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1247 printf (_("** host: %s\n"),
1248 uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1249 printf (_("** port: %s\n"),
1250 uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE));
1251 if (uri.hostData.ip4) {
1252 inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr));
1253 printf (_("** IPv4: %s\n"), ipstr);
1254 }
1255 if (uri.hostData.ip6) {
1256 inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr));
1257 printf (_("** IPv6: %s\n"), ipstr);
1258 }
1259 if (uri.pathHead) {
1260 printf (_("** path: "));
1261 const UriPathSegmentA* p = uri.pathHead;
1262 for (; p; p = p->next) {
1263 printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE));
1264 }
1265 puts ("");
1266 }
1267 if (uri.query.first) {
1268 printf (_("** query: %s\n"),
1269 uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE));
1270 }
1271 if (uri.fragment.first) {
1272 printf (_("** fragment: %s\n"),
1273 uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE));
1274 }
1275 }
1276
1277 if (!uri_strcmp (uri.scheme, "https"))
1278 use_ssl = true;
1279 else
1280 use_ssl = false;
1281
1282 /* we do a sloppy test here only, because uriparser would have failed
1283 * above, if the port would be invalid, we just check for MAX_PORT
1284 */
1285 if (uri.portText.first) {
1286 new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE));
1287 } else {
1288 new_port = HTTP_PORT;
1289 if (use_ssl)
1290 new_port = HTTPS_PORT;
1291 }
1292 if (new_port > MAX_PORT)
1293 die (STATE_UNKNOWN,
1294 _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"),
1295 MAX_PORT, location, display_html ? "</A>" : "");
1296
1297 /* by RFC 7231 relative URLs in Location should be taken relative to
1298 * the original URL, so wy try to form a new absolute URL here
1299 */
1300 if (!uri.scheme.first && !uri.hostText.first) {
1301 new_host = strdup (host_name ? host_name : server_address);
1302 } else {
1303 new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1304 }
1305
1306 /* compose new path */
1307 /* TODO: handle fragments and query part of URL */
1308 new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE);
1309 if (uri.pathHead) {
1310 const UriPathSegmentA* p = uri.pathHead;
1311 for (; p; p = p->next) {
1312 strncat (new_url, "/", DEFAULT_BUFFER_SIZE);
1313 strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1);
1314 }
1315 }
1316
1317 if (server_port==new_port &&
1318 !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1319 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
1320 !strcmp(server_url, new_url))
1321 die (STATE_CRITICAL,
1322 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1323 use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : ""));
1324
1325 /* set new values for redirected request */
1326
1327 if (!(followsticky & STICKY_HOST)) {
1328 free (server_address);
1329 server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH);
1330 }
1331 if (!(followsticky & STICKY_PORT)) {
1332 server_port = (unsigned short)new_port;
1333 }
1334
1335 free (host_name);
1336 host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH);
1337
1338 /* reset virtual port */
1339 virtual_port = server_port;
1340
1341 free(new_host);
1342 free (server_url);
1343 server_url = new_url;
1344
1345 uriFreeUriMembersA (&uri);
1346
1347 if (verbose)
1348 printf (_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http",
1349 host_name ? host_name : server_address, server_port, server_url);
1350
1351 /* TODO: the hash component MUST be taken from the original URL and
1352 * attached to the URL in Location
1353 */
1354
1355 cleanup ();
1356 check_http ();
1357}
1358
1359/* check whether a file exists */
1360void
1361test_file (char *path)
1362{
1363 if (access(path, R_OK) == 0)
1364 return;
1365 usage2 (_("file does not exist or is not readable"), path);
1366}
1367
1368bool
1369process_arguments (int argc, char **argv)
1370{
1371 char *p;
1372 int c = 1;
1373 char *temp;
1374
1375 enum {
1376 INVERT_REGEX = CHAR_MAX + 1,
1377 SNI_OPTION,
1378 MAX_REDIRS_OPTION,
1379 CONTINUE_AFTER_CHECK_CERT,
1380 CA_CERT_OPTION,
1381 HTTP_VERSION_OPTION,
1382 AUTOMATIC_DECOMPRESSION,
1383 COOKIE_JAR
1384 };
1385
1386 int option = 0;
1387 int got_plus = 0;
1388 static struct option longopts[] = {
1389 STD_LONG_OPTS,
1390 {"link", no_argument, 0, 'L'},
1391 {"nohtml", no_argument, 0, 'n'},
1392 {"ssl", optional_argument, 0, 'S'},
1393 {"sni", no_argument, 0, SNI_OPTION},
1394 {"post", required_argument, 0, 'P'},
1395 {"method", required_argument, 0, 'j'},
1396 {"IP-address", required_argument, 0, 'I'},
1397 {"url", required_argument, 0, 'u'},
1398 {"port", required_argument, 0, 'p'},
1399 {"authorization", required_argument, 0, 'a'},
1400 {"proxy-authorization", required_argument, 0, 'b'},
1401 {"header-string", required_argument, 0, 'd'},
1402 {"string", required_argument, 0, 's'},
1403 {"expect", required_argument, 0, 'e'},
1404 {"regex", required_argument, 0, 'r'},
1405 {"ereg", required_argument, 0, 'r'},
1406 {"eregi", required_argument, 0, 'R'},
1407 {"linespan", no_argument, 0, 'l'},
1408 {"onredirect", required_argument, 0, 'f'},
1409 {"certificate", required_argument, 0, 'C'},
1410 {"client-cert", required_argument, 0, 'J'},
1411 {"private-key", required_argument, 0, 'K'},
1412 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1413 {"verify-cert", no_argument, 0, 'D'},
1414 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1415 {"useragent", required_argument, 0, 'A'},
1416 {"header", required_argument, 0, 'k'},
1417 {"no-body", no_argument, 0, 'N'},
1418 {"max-age", required_argument, 0, 'M'},
1419 {"content-type", required_argument, 0, 'T'},
1420 {"pagesize", required_argument, 0, 'm'},
1421 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1422 {"use-ipv4", no_argument, 0, '4'},
1423 {"use-ipv6", no_argument, 0, '6'},
1424 {"extended-perfdata", no_argument, 0, 'E'},
1425 {"show-body", no_argument, 0, 'B'},
1426 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1427 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1428 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1429 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1430 {0, 0, 0, 0}
1431 };
1432
1433 if (argc < 2)
1434 return false;
1435
1436 /* support check_http compatible arguments */
1437 for (c = 1; c < argc; c++) {
1438 if (strcmp ("-to", argv[c]) == 0)
1439 strcpy (argv[c], "-t");
1440 if (strcmp ("-hn", argv[c]) == 0)
1441 strcpy (argv[c], "-H");
1442 if (strcmp ("-wt", argv[c]) == 0)
1443 strcpy (argv[c], "-w");
1444 if (strcmp ("-ct", argv[c]) == 0)
1445 strcpy (argv[c], "-c");
1446 if (strcmp ("-nohtml", argv[c]) == 0)
1447 strcpy (argv[c], "-n");
1448 }
1449
1450 server_url = strdup(DEFAULT_SERVER_URL);
1451
1452 while (1) {
1453 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option);
1454 if (c == -1 || c == EOF || c == 1)
1455 break;
1456
1457 switch (c) {
1458 case 'h':
1459 print_help();
1460 exit(STATE_UNKNOWN);
1461 break;
1462 case 'V':
1463 print_revision(progname, NP_VERSION);
1464 print_curl_version();
1465 exit(STATE_UNKNOWN);
1466 break;
1467 case 'v':
1468 verbose++;
1469 break;
1470 case 't': /* timeout period */
1471 if (!is_intnonneg (optarg))
1472 usage2 (_("Timeout interval must be a positive integer"), optarg);
1473 else
1474 socket_timeout = (int)strtol (optarg, NULL, 10);
1475 break;
1476 case 'c': /* critical time threshold */
1477 critical_thresholds = optarg;
1478 break;
1479 case 'w': /* warning time threshold */
1480 warning_thresholds = optarg;
1481 break;
1482 case 'H': /* virtual host */
1483 host_name = strdup (optarg);
1484 if (host_name[0] == '[') {
1485 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */
1486 virtual_port = atoi (p + 2);
1487 /* cut off the port */
1488 host_name_length = strlen (host_name) - strlen (p) - 1;
1489 free (host_name);
1490 host_name = strndup (optarg, host_name_length);
1491 }
1492 } else if ((p = strchr (host_name, ':')) != NULL
1493 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */
1494 virtual_port = atoi (p);
1495 /* cut off the port */
1496 host_name_length = strlen (host_name) - strlen (p) - 1;
1497 free (host_name);
1498 host_name = strndup (optarg, host_name_length);
1499 }
1500 break;
1501 case 'I': /* internet address */
1502 server_address = strdup (optarg);
1503 break;
1504 case 'u': /* URL path */
1505 server_url = strdup (optarg);
1506 break;
1507 case 'p': /* Server port */
1508 if (!is_intnonneg (optarg))
1509 usage2 (_("Invalid port number, expecting a non-negative number"), optarg);
1510 else {
1511 if( strtol(optarg, NULL, 10) > MAX_PORT)
1512 usage2 (_("Invalid port number, supplied port number is too big"), optarg);
1513 server_port = (unsigned short)strtol(optarg, NULL, 10);
1514 specify_port = true;
1515 }
1516 break;
1517 case 'a': /* authorization info */
1518 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
1519 user_auth[MAX_INPUT_BUFFER - 1] = 0;
1520 break;
1521 case 'b': /* proxy-authorization info */
1522 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1523 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1524 break;
1525 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1526 if (! http_post_data)
1527 http_post_data = strdup (optarg);
1528 if (! http_method)
1529 http_method = strdup("POST");
1530 break;
1531 case 'j': /* Set HTTP method */
1532 if (http_method)
1533 free(http_method);
1534 http_method = strdup (optarg);
1535 break;
1536 case 'A': /* useragent */
1537 strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE);
1538 user_agent[DEFAULT_BUFFER_SIZE-1] = '\0';
1539 break;
1540 case 'k': /* Additional headers */
1541 if (http_opt_headers_count == 0)
1542 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
1543 else
1544 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
1545 http_opt_headers[http_opt_headers_count - 1] = optarg;
1546 break;
1547 case 'L': /* show html link */
1548 display_html = true;
1549 break;
1550 case 'n': /* do not show html link */
1551 display_html = false;
1552 break;
1553 case 'C': /* Check SSL cert validity */
1554#ifdef LIBCURL_FEATURE_SSL
1555 if ((temp=strchr(optarg,','))!=NULL) {
1556 *temp='\0';
1557 if (!is_intnonneg (optarg))
1558 usage2 (_("Invalid certificate expiration period"), optarg);
1559 days_till_exp_warn = atoi(optarg);
1560 *temp=',';
1561 temp++;
1562 if (!is_intnonneg (temp))
1563 usage2 (_("Invalid certificate expiration period"), temp);
1564 days_till_exp_crit = atoi (temp);
1565 }
1566 else {
1567 days_till_exp_crit=0;
1568 if (!is_intnonneg (optarg))
1569 usage2 (_("Invalid certificate expiration period"), optarg);
1570 days_till_exp_warn = atoi (optarg);
1571 }
1572 check_cert = true;
1573 goto enable_ssl;
1574#endif
1575 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1576#ifdef HAVE_SSL
1577 continue_after_check_cert = true;
1578 break;
1579#endif
1580 case 'J': /* use client certificate */
1581#ifdef LIBCURL_FEATURE_SSL
1582 test_file(optarg);
1583 client_cert = optarg;
1584 goto enable_ssl;
1585#endif
1586 case 'K': /* use client private key */
1587#ifdef LIBCURL_FEATURE_SSL
1588 test_file(optarg);
1589 client_privkey = optarg;
1590 goto enable_ssl;
1591#endif
1592#ifdef LIBCURL_FEATURE_SSL
1593 case CA_CERT_OPTION: /* use CA chain file */
1594 test_file(optarg);
1595 ca_cert = optarg;
1596 goto enable_ssl;
1597#endif
1598#ifdef LIBCURL_FEATURE_SSL
1599 case 'D': /* verify peer certificate & host */
1600 verify_peer_and_host = true;
1601 break;
1602#endif
1603 case 'S': /* use SSL */
1604#ifdef LIBCURL_FEATURE_SSL
1605 enable_ssl:
1606 use_ssl = true;
1607 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1608 * Only set if it's non-zero. This helps when we include multiple
1609 * parameters, like -S and -C combinations */
1610 ssl_version = CURL_SSLVERSION_DEFAULT;
1611 if (c=='S' && optarg != NULL) {
1612 char *plus_ptr = strchr(optarg, '+');
1613 if (plus_ptr) {
1614 got_plus = 1;
1615 *plus_ptr = '\0';
1616 }
1617
1618 if (optarg[0] == '2')
1619 ssl_version = CURL_SSLVERSION_SSLv2;
1620 else if (optarg[0] == '3')
1621 ssl_version = CURL_SSLVERSION_SSLv3;
1622 else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0"))
1623#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1624 ssl_version = CURL_SSLVERSION_TLSv1_0;
1625#else
1626 ssl_version = CURL_SSLVERSION_DEFAULT;
1627#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1628 else if (!strcmp (optarg, "1.1"))
1629#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1630 ssl_version = CURL_SSLVERSION_TLSv1_1;
1631#else
1632 ssl_version = CURL_SSLVERSION_DEFAULT;
1633#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1634 else if (!strcmp (optarg, "1.2"))
1635#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1636 ssl_version = CURL_SSLVERSION_TLSv1_2;
1637#else
1638 ssl_version = CURL_SSLVERSION_DEFAULT;
1639#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1640 else if (!strcmp (optarg, "1.3"))
1641#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1642 ssl_version = CURL_SSLVERSION_TLSv1_3;
1643#else
1644 ssl_version = CURL_SSLVERSION_DEFAULT;
1645#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1646 else
1647 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1648 }
1649#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1650 if (got_plus) {
1651 switch (ssl_version) {
1652 case CURL_SSLVERSION_TLSv1_3:
1653 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1654 break;
1655 case CURL_SSLVERSION_TLSv1_2:
1656 case CURL_SSLVERSION_TLSv1_1:
1657 case CURL_SSLVERSION_TLSv1_0:
1658 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1659 break;
1660 }
1661 } else {
1662 switch (ssl_version) {
1663 case CURL_SSLVERSION_TLSv1_3:
1664 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1665 break;
1666 case CURL_SSLVERSION_TLSv1_2:
1667 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1668 break;
1669 case CURL_SSLVERSION_TLSv1_1:
1670 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1671 break;
1672 case CURL_SSLVERSION_TLSv1_0:
1673 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1674 break;
1675 }
1676 }
1677#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1678 if (verbose >= 2)
1679 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1680 if (!specify_port)
1681 server_port = HTTPS_PORT;
1682 break;
1683#else /* LIBCURL_FEATURE_SSL */
1684 /* -C -J and -K fall through to here without SSL */
1685 usage4 (_("Invalid option - SSL is not available"));
1686 break;
1687 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1688 use_sni = true;
1689 break;
1690#endif /* LIBCURL_FEATURE_SSL */
1691 case MAX_REDIRS_OPTION:
1692 if (!is_intnonneg (optarg))
1693 usage2 (_("Invalid max_redirs count"), optarg);
1694 else {
1695 max_depth = atoi (optarg);
1696 }
1697 break;
1698 case 'f': /* onredirect */
1699 if (!strcmp (optarg, "ok"))
1700 onredirect = STATE_OK;
1701 else if (!strcmp (optarg, "warning"))
1702 onredirect = STATE_WARNING;
1703 else if (!strcmp (optarg, "critical"))
1704 onredirect = STATE_CRITICAL;
1705 else if (!strcmp (optarg, "unknown"))
1706 onredirect = STATE_UNKNOWN;
1707 else if (!strcmp (optarg, "follow"))
1708 onredirect = STATE_DEPENDENT;
1709 else if (!strcmp (optarg, "stickyport"))
1710 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT;
1711 else if (!strcmp (optarg, "sticky"))
1712 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
1713 else if (!strcmp (optarg, "follow"))
1714 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
1715 else if (!strcmp (optarg, "curl"))
1716 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
1717 else usage2 (_("Invalid onredirect option"), optarg);
1718 if (verbose >= 2)
1719 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
1720 break;
1721 case 'd': /* string or substring */
1722 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1);
1723 header_expect[MAX_INPUT_BUFFER - 1] = 0;
1724 break;
1725 case 's': /* string or substring */
1726 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
1727 string_expect[MAX_INPUT_BUFFER - 1] = 0;
1728 break;
1729 case 'e': /* string or substring */
1730 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
1731 server_expect[MAX_INPUT_BUFFER - 1] = 0;
1732 server_expect_yn = 1;
1733 break;
1734 case 'T': /* Content-type */
1735 http_content_type = strdup (optarg);
1736 break;
1737 case 'l': /* linespan */
1738 cflags &= ~REG_NEWLINE;
1739 break;
1740 case 'R': /* regex */
1741 cflags |= REG_ICASE;
1742 // fall through
1743 case 'r': /* regex */
1744 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
1745 regexp[MAX_RE_SIZE - 1] = 0;
1746 errcode = regcomp (&preg, regexp, cflags);
1747 if (errcode != 0) {
1748 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1749 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
1750 return false;
1751 }
1752 break;
1753 case INVERT_REGEX:
1754 invert_regex = true;
1755 break;
1756 case '4':
1757 address_family = AF_INET;
1758 break;
1759 case '6':
1760#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6)
1761 address_family = AF_INET6;
1762#else
1763 usage4 (_("IPv6 support not available"));
1764#endif
1765 break;
1766 case 'm': /* min_page_length */
1767 {
1768 char *tmp;
1769 if (strchr(optarg, ':') != (char *)NULL) {
1770 /* range, so get two values, min:max */
1771 tmp = strtok(optarg, ":");
1772 if (tmp == NULL) {
1773 printf("Bad format: try \"-m min:max\"\n");
1774 exit (STATE_WARNING);
1775 } else
1776 min_page_len = atoi(tmp);
1777
1778 tmp = strtok(NULL, ":");
1779 if (tmp == NULL) {
1780 printf("Bad format: try \"-m min:max\"\n");
1781 exit (STATE_WARNING);
1782 } else
1783 max_page_len = atoi(tmp);
1784 } else
1785 min_page_len = atoi (optarg);
1786 break;
1787 }
1788 case 'N': /* no-body */
1789 no_body = true;
1790 break;
1791 case 'M': /* max-age */
1792 {
1793 int L = strlen(optarg);
1794 if (L && optarg[L-1] == 'm')
1795 maximum_age = atoi (optarg) * 60;
1796 else if (L && optarg[L-1] == 'h')
1797 maximum_age = atoi (optarg) * 60 * 60;
1798 else if (L && optarg[L-1] == 'd')
1799 maximum_age = atoi (optarg) * 60 * 60 * 24;
1800 else if (L && (optarg[L-1] == 's' ||
1801 isdigit (optarg[L-1])))
1802 maximum_age = atoi (optarg);
1803 else {
1804 fprintf (stderr, "unparsable max-age: %s\n", optarg);
1805 exit (STATE_WARNING);
1806 }
1807 if (verbose >= 2)
1808 printf ("* Maximal age of document set to %d seconds\n", maximum_age);
1809 }
1810 break;
1811 case 'E': /* show extended perfdata */
1812 show_extended_perfdata = true;
1813 break;
1814 case 'B': /* print body content after status line */
1815 show_body = true;
1816 break;
1817 case HTTP_VERSION_OPTION:
1818 curl_http_version = CURL_HTTP_VERSION_NONE;
1819 if (strcmp (optarg, "1.0") == 0) {
1820 curl_http_version = CURL_HTTP_VERSION_1_0;
1821 } else if (strcmp (optarg, "1.1") == 0) {
1822 curl_http_version = CURL_HTTP_VERSION_1_1;
1823 } else if ((strcmp (optarg, "2.0") == 0) || (strcmp (optarg, "2") == 0)) {
1824#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1825 curl_http_version = CURL_HTTP_VERSION_2_0;
1826#else
1827 curl_http_version = CURL_HTTP_VERSION_NONE;
1828#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1829 } else {
1830 fprintf (stderr, "unknown http-version parameter: %s\n", optarg);
1831 exit (STATE_WARNING);
1832 }
1833 break;
1834 case AUTOMATIC_DECOMPRESSION:
1835 automatic_decompression = true;
1836 break;
1837 case COOKIE_JAR:
1838 cookie_jar_file = optarg;
1839 break;
1840 case '?':
1841 /* print short usage statement if args not parsable */
1842 usage5 ();
1843 break;
1844 }
1845 }
1846
1847 c = optind;
1848
1849 if (server_address == NULL && c < argc)
1850 server_address = strdup (argv[c++]);
1851
1852 if (host_name == NULL && c < argc)
1853 host_name = strdup (argv[c++]);
1854
1855 if (server_address == NULL) {
1856 if (host_name == NULL)
1857 usage4 (_("You must specify a server address or host name"));
1858 else
1859 server_address = strdup (host_name);
1860 }
1861
1862 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
1863
1864 if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
1865 socket_timeout = (int)thlds->critical->end + 1;
1866 if (verbose >= 2)
1867 printf ("* Socket timeout set to %ld seconds\n", socket_timeout);
1868
1869 if (http_method == NULL)
1870 http_method = strdup ("GET");
1871
1872 if (client_cert && !client_privkey)
1873 usage4 (_("If you use a client certificate you must also specify a private key file"));
1874
1875 if (virtual_port == 0)
1876 virtual_port = server_port;
1877 else {
1878 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1879 if(!specify_port)
1880 server_port = virtual_port;
1881 }
1882
1883 return true;
1884}
1885
1886char *perfd_time (double elapsed_time)
1887{
1888 return fperfdata ("time", elapsed_time, "s",
1889 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1890 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1891 true, 0, true, socket_timeout);
1892}
1893
1894char *perfd_time_connect (double elapsed_time_connect)
1895{
1896 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1897}
1898
1899char *perfd_time_ssl (double elapsed_time_ssl)
1900{
1901 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1902}
1903
1904char *perfd_time_headers (double elapsed_time_headers)
1905{
1906 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1907}
1908
1909char *perfd_time_firstbyte (double elapsed_time_firstbyte)
1910{
1911 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1912}
1913
1914char *perfd_time_transfer (double elapsed_time_transfer)
1915{
1916 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1917}
1918
1919char *perfd_size (int page_len)
1920{
1921 return perfdata ("size", page_len, "B",
1922 (min_page_len>0?true:false), min_page_len,
1923 (min_page_len>0?true:false), 0,
1924 true, 0, false, 0);
1925}
1926
1927void
1928print_help (void)
1929{
1930 print_revision (progname, NP_VERSION);
1931
1932 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1933 printf (COPYRIGHT, copyright, email);
1934
1935 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1936 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1937 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1938 printf ("%s\n", _("certificate expiration times."));
1939 printf ("\n");
1940 printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1941 printf ("%s\n", _("as possible."));
1942
1943 printf ("\n\n");
1944
1945 print_usage ();
1946
1947 printf (_("NOTE: One or both of -H and -I must be specified"));
1948
1949 printf ("\n");
1950
1951 printf (UT_HELP_VRSN);
1952 printf (UT_EXTRA_OPTS);
1953
1954 printf (" %s\n", "-H, --hostname=ADDRESS");
1955 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1956 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1957 printf (" %s\n", "-I, --IP-address=ADDRESS");
1958 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1959 printf (" %s\n", "-p, --port=INTEGER");
1960 printf (" %s", _("Port number (default: "));
1961 printf ("%d)\n", HTTP_PORT);
1962
1963 printf (UT_IPv46);
1964
1965#ifdef LIBCURL_FEATURE_SSL
1966 printf (" %s\n", "-S, --ssl=VERSION[+]");
1967 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1968 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1969 printf (" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted."));
1970 printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl"));
1971 printf (" %s\n", "--sni");
1972 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1973#if LIBCURL_VERSION_NUM >= 0x071801
1974 printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
1975 printf (" %s\n", _(" SNI only really works since TLSv1.0"));
1976#else
1977 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
1978#endif
1979 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1980 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1981 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
1982 printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
1983 printf (" %s\n", "--continue-after-certificate");
1984 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
1985 printf (" %s\n", _("Does nothing unless -C is used."));
1986 printf (" %s\n", "-J, --client-cert=FILE");
1987 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1988 printf (" %s\n", _("to be used in establishing the SSL session"));
1989 printf (" %s\n", "-K, --private-key=FILE");
1990 printf (" %s\n", _("Name of file containing the private key (PEM format)"));
1991 printf (" %s\n", _("matching the client certificate"));
1992 printf (" %s\n", "--ca-cert=FILE");
1993 printf (" %s\n", _("CA certificate file to verify peer against"));
1994 printf (" %s\n", "-D, --verify-cert");
1995 printf (" %s\n", _("Verify the peer's SSL certificate and hostname"));
1996#endif
1997
1998 printf (" %s\n", "-e, --expect=STRING");
1999 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
2000 printf (" %s", _("the first (status) line of the server response (default: "));
2001 printf ("%s)\n", HTTP_EXPECT);
2002 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
2003 printf (" %s\n", "-d, --header-string=STRING");
2004 printf (" %s\n", _("String to expect in the response headers"));
2005 printf (" %s\n", "-s, --string=STRING");
2006 printf (" %s\n", _("String to expect in the content"));
2007 printf (" %s\n", "-u, --url=PATH");
2008 printf (" %s\n", _("URL to GET or POST (default: /)"));
2009 printf (" %s\n", "-P, --post=STRING");
2010 printf (" %s\n", _("URL encoded http POST data"));
2011 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
2012 printf (" %s\n", _("Set HTTP method."));
2013 printf (" %s\n", "-N, --no-body");
2014 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
2015 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
2016 printf (" %s\n", "-M, --max-age=SECONDS");
2017 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
2018 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
2019 printf (" %s\n", "-T, --content-type=STRING");
2020 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
2021 printf (" %s\n", "-l, --linespan");
2022 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
2023 printf (" %s\n", "-r, --regex, --ereg=STRING");
2024 printf (" %s\n", _("Search page for regex STRING"));
2025 printf (" %s\n", "-R, --eregi=STRING");
2026 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
2027 printf (" %s\n", "--invert-regex");
2028 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
2029 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
2030 printf (" %s\n", _("Username:password on sites with basic authentication"));
2031 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
2032 printf (" %s\n", _("Username:password on proxy-servers with basic authentication"));
2033 printf (" %s\n", "-A, --useragent=STRING");
2034 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
2035 printf (" %s\n", "-k, --header=STRING");
2036 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
2037 printf (" %s\n", "-E, --extended-perfdata");
2038 printf (" %s\n", _("Print additional performance data"));
2039 printf (" %s\n", "-B, --show-body");
2040 printf (" %s\n", _("Print body content below status line"));
2041 printf (" %s\n", "-L, --link");
2042 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
2043 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
2044 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
2045 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
2046 printf (" %s\n", _("follow uses the old redirection algorithm of check_http."));
2047 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2048 printf (" %s\n", "--max-redirs=INTEGER");
2049 printf (" %s", _("Maximal number of redirects (default: "));
2050 printf ("%d)\n", DEFAULT_MAX_REDIRS);
2051 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2052 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2053 printf ("\n");
2054 printf (" %s\n", "--http-version=VERSION");
2055 printf (" %s\n", _("Connect via specific HTTP protocol."));
2056 printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
2057 printf (" %s\n", "--enable-automatic-decompression");
2058 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2059 printf (" %s\n", "---cookie-jar=FILE");
2060 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2061 printf ("\n");
2062
2063 printf (UT_WARN_CRIT);
2064
2065 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
2066
2067 printf (UT_VERBOSE);
2068
2069 printf ("\n");
2070 printf ("%s\n", _("Notes:"));
2071 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2072 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2073 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2074 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2075 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2076 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2077
2078#ifdef LIBCURL_FEATURE_SSL
2079 printf ("\n");
2080 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
2081 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
2082 printf (" %s\n", _("certificate is still valid for the specified number of days."));
2083 printf ("\n");
2084 printf (" %s\n", _("Please note that this plugin does not check if the presented server"));
2085 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
2086 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2087 printf ("\n");
2088 printf ("%s\n", _("Examples:"));
2089 printf (" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
2090 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
2091 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2092 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2093 printf (" %s\n", _("a STATE_CRITICAL will be returned."));
2094 printf ("\n");
2095 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
2096 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
2097 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2098 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
2099 printf (" %s\n\n", _("the certificate is expired."));
2100 printf ("\n");
2101 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
2102 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
2103 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2104 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
2105 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2106#endif
2107
2108 printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2109 printf (" %s\n", _("It is recommended to use an environment proxy like:"));
2110 printf (" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2111 printf (" %s\n", _("legacy proxy requests in check_http style still work:"));
2112 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
2113
2114#ifdef LIBCURL_FEATURE_SSL
2115 printf ("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
2116 printf (" %s\n", _("It is recommended to use an environment proxy like:"));
2117 printf (" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
2118 printf (" %s\n", _("legacy proxy requests in check_http style still work:"));
2119 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com "));
2120 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
2121 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2122 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2123 printf (" %s\n", _("a STATE_CRITICAL will be returned."));
2124
2125#endif
2126
2127 printf (UT_SUPPORT);
2128
2129}
2130
2131
2132
2133void
2134print_usage (void)
2135{
2136 printf ("%s\n", _("Usage:"));
2137 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
2138 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
2139 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2140 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2141 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
2142 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2143 printf (" [-A string] [-k string] [-S <version>] [--sni]\n");
2144 printf (" [-T <content-type>] [-j method]\n");
2145 printf (" [--http-version=<version>] [--enable-automatic-decompression]\n");
2146 printf (" [--cookie-jar=<cookie jar file>\n");
2147 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
2148 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2149 printf ("\n");
2150#ifdef LIBCURL_FEATURE_SSL
2151 printf ("%s\n", _("In the first form, make an HTTP request."));
2152 printf ("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
2153#endif
2154 printf ("%s\n", _("WARNING: check_curl is experimental. Please use"));
2155 printf ("%s\n\n", _("check_http if you need a stable version."));
2156}
2157
2158void
2159print_curl_version (void)
2160{
2161 printf( "%s\n", curl_version());
2162}
2163
2164int
2165curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf)
2166{
2167 buf->bufsize = DEFAULT_BUFFER_SIZE;
2168 buf->buflen = 0;
2169 buf->buf = (char *)malloc ((size_t)buf->bufsize);
2170 if (buf->buf == NULL) return -1;
2171 return 0;
2172}
2173
2174int
2175curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream)
2176{
2177 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2178
2179 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
2180 buf->bufsize = buf->bufsize * 2;
2181 buf->buf = (char *)realloc (buf->buf, buf->bufsize);
2182 if (buf->buf == NULL) {
2183 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2184 return -1;
2185 }
2186 }
2187
2188 memcpy (buf->buf + buf->buflen, buffer, size * nmemb);
2189 buf->buflen += size * nmemb;
2190 buf->buf[buf->buflen] = '\0';
2191
2192 return (int)(size * nmemb);
2193}
2194
2195int
2196curlhelp_buffer_read_callback (void *buffer, size_t size, size_t nmemb, void *stream)
2197{
2198 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2199
2200 size_t n = min (nmemb * size, buf->buflen - buf->pos);
2201
2202 memcpy (buffer, buf->buf + buf->pos, n);
2203 buf->pos += n;
2204
2205 return (int)n;
2206}
2207
2208void
2209curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf)
2210{
2211 free (buf->buf);
2212 buf->buf = NULL;
2213}
2214
2215int
2216curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen)
2217{
2218 buf->buflen = datalen;
2219 buf->buf = (char *)malloc ((size_t)buf->buflen);
2220 if (buf->buf == NULL) return -1;
2221 memcpy (buf->buf, data, datalen);
2222 buf->pos = 0;
2223 return 0;
2224}
2225
2226void
2227curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf)
2228{
2229 free (buf->buf);
2230 buf->buf = NULL;
2231}
2232
2233/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2234 */
2235const char*
2236strrstr2(const char *haystack, const char *needle)
2237{
2238 int counter;
2239 size_t len;
2240 const char *prev_pos;
2241 const char *pos;
2242
2243 if (haystack == NULL || needle == NULL)
2244 return NULL;
2245
2246 if (haystack[0] == '\0' || needle[0] == '\0')
2247 return NULL;
2248
2249 counter = 0;
2250 prev_pos = NULL;
2251 pos = haystack;
2252 len = strlen (needle);
2253 for (;;) {
2254 pos = strstr (pos, needle);
2255 if (pos == NULL) {
2256 if (counter == 0)
2257 return NULL;
2258 else
2259 return prev_pos;
2260 }
2261 counter++;
2262 prev_pos = pos;
2263 pos += len;
2264 if (*pos == '\0') return prev_pos;
2265 }
2266}
2267
2268int
2269curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
2270{
2271 char *first_line_end;
2272 char *p;
2273 size_t first_line_len;
2274 char *pp;
2275 const char *start;
2276 char *first_line_buf;
2277
2278 /* find last start of a new header */
2279 start = strrstr2 (buf, "\r\nHTTP/");
2280 if (start != NULL) {
2281 start += 2;
2282 buf = start;
2283 }
2284
2285 first_line_end = strstr(buf, "\r\n");
2286 if (first_line_end == NULL) return -1;
2287
2288 first_line_len = (size_t)(first_line_end - buf);
2289 status_line->first_line = (char *)malloc (first_line_len + 1);
2290 if (status_line->first_line == NULL) return -1;
2291 memcpy (status_line->first_line, buf, first_line_len);
2292 status_line->first_line[first_line_len] = '\0';
2293 first_line_buf = strdup( status_line->first_line );
2294
2295 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2296
2297 p = strtok(first_line_buf, "/");
2298 if( p == NULL ) { free( first_line_buf ); return -1; }
2299 if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
2300
2301 p = strtok( NULL, " " );
2302 if( p == NULL ) { free( first_line_buf ); return -1; }
2303 if( strchr( p, '.' ) != NULL ) {
2304
2305 /* HTTP 1.x case */
2306 strtok( p, "." );
2307 status_line->http_major = (int)strtol( p, &pp, 10 );
2308 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2309 strtok( NULL, " " );
2310 status_line->http_minor = (int)strtol( p, &pp, 10 );
2311 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2312 p += 4; /* 1.x SP */
2313 } else {
2314 /* HTTP 2 case */
2315 status_line->http_major = (int)strtol( p, &pp, 10 );
2316 status_line->http_minor = 0;
2317 p += 2; /* 2 SP */
2318 }
2319
2320 /* status code: "404" or "404.1", then SP */
2321
2322 p = strtok( p, " " );
2323 if( p == NULL ) { free( first_line_buf ); return -1; }
2324 if( strchr( p, '.' ) != NULL ) {
2325 char *ppp;
2326 ppp = strtok( p, "." );
2327 status_line->http_code = (int)strtol( ppp, &pp, 10 );
2328 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2329 ppp = strtok( NULL, "" );
2330 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
2331 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2332 p += 6; /* 400.1 SP */
2333 } else {
2334 status_line->http_code = (int)strtol( p, &pp, 10 );
2335 status_line->http_subcode = -1;
2336 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2337 p += 4; /* 400 SP */
2338 }
2339
2340 /* Human readable message: "Not Found" CRLF */
2341
2342 p = strtok( p, "" );
2343 if( p == NULL ) { status_line->msg = ""; return 0; }
2344 status_line->msg = status_line->first_line + ( p - first_line_buf );
2345 free( first_line_buf );
2346
2347 return 0;
2348}
2349
2350void
2351curlhelp_free_statusline (curlhelp_statusline *status_line)
2352{
2353 free (status_line->first_line);
2354}
2355
2356void
2357remove_newlines (char *s)
2358{
2359 char *p;
2360
2361 for (p = s; *p != '\0'; p++)
2362 if (*p == '\r' || *p == '\n')
2363 *p = ' ';
2364}
2365
2366char *
2367get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header)
2368{
2369 int i;
2370 for( i = 0; i < nof_headers; i++ ) {
2371 if(headers[i].name != NULL && strncasecmp( header, headers[i].name, max( headers[i].name_len, 4 ) ) == 0 ) {
2372 return strndup( headers[i].value, headers[i].value_len );
2373 }
2374 }
2375 return NULL;
2376}
2377
2378int
2379check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE])
2380{
2381 char *server_date = NULL;
2382 char *document_date = NULL;
2383 int date_result = STATE_OK;
2384 curlhelp_statusline status_line;
2385 struct phr_header headers[255];
2386 size_t nof_headers = 255;
2387 size_t msglen;
2388
2389 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2390 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2391 headers, &nof_headers, 0);
2392
2393 server_date = get_header_value (headers, nof_headers, "date");
2394 document_date = get_header_value (headers, nof_headers, "last-modified");
2395
2396 if (!server_date || !*server_date) {
2397 char tmp[DEFAULT_BUFFER_SIZE];
2398
2399 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2400 strcpy(*msg, tmp);
2401
2402 date_result = max_state_alt(STATE_UNKNOWN, date_result);
2403
2404 } else if (!document_date || !*document_date) {
2405 char tmp[DEFAULT_BUFFER_SIZE];
2406
2407 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2408 strcpy(*msg, tmp);
2409
2410 date_result = max_state_alt(STATE_CRITICAL, date_result);
2411
2412 } else {
2413 time_t srv_data = curl_getdate (server_date, NULL);
2414 time_t doc_data = curl_getdate (document_date, NULL);
2415 if (verbose >= 2)
2416 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2417 if (srv_data <= 0) {
2418 char tmp[DEFAULT_BUFFER_SIZE];
2419
2420 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2421 strcpy(*msg, tmp);
2422
2423 date_result = max_state_alt(STATE_CRITICAL, date_result);
2424 } else if (doc_data <= 0) {
2425 char tmp[DEFAULT_BUFFER_SIZE];
2426
2427 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2428 strcpy(*msg, tmp);
2429
2430 date_result = max_state_alt(STATE_CRITICAL, date_result);
2431 } else if (doc_data > srv_data + 30) {
2432 char tmp[DEFAULT_BUFFER_SIZE];
2433
2434 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2435 strcpy(*msg, tmp);
2436
2437 date_result = max_state_alt(STATE_CRITICAL, date_result);
2438 } else if (doc_data < srv_data - maximum_age) {
2439 int n = (srv_data - doc_data);
2440 if (n > (60 * 60 * 24 * 2)) {
2441 char tmp[DEFAULT_BUFFER_SIZE];
2442
2443 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
2444 strcpy(*msg, tmp);
2445
2446 date_result = max_state_alt(STATE_CRITICAL, date_result);
2447 } else {
2448 char tmp[DEFAULT_BUFFER_SIZE];
2449
2450 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2451 strcpy(*msg, tmp);
2452
2453 date_result = max_state_alt(STATE_CRITICAL, date_result);
2454 }
2455 }
2456 }
2457
2458 if (server_date) free (server_date);
2459 if (document_date) free (document_date);
2460
2461 return date_result;
2462}
2463
2464
2465int
2466get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf)
2467{
2468 const char *s;
2469 int content_length = 0;
2470 char *copy;
2471 struct phr_header headers[255];
2472 size_t nof_headers = 255;
2473 size_t msglen;
2474 char *content_length_s = NULL;
2475 curlhelp_statusline status_line;
2476
2477 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2478 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2479 headers, &nof_headers, 0);
2480
2481 content_length_s = get_header_value (headers, nof_headers, "content-length");
2482 if (!content_length_s) {
2483 return header_buf->buflen + body_buf->buflen;
2484 }
2485 content_length_s += strspn (content_length_s, " \t");
2486 content_length = atoi (content_length_s);
2487 if (content_length != body_buf->buflen) {
2488 /* TODO: should we warn if the actual and the reported body length don't match? */
2489 }
2490
2491 if (content_length_s) free (content_length_s);
2492
2493 return header_buf->buflen + body_buf->buflen;
2494}
2495
2496/* TODO: is there a better way in libcurl to check for the SSL library? */
2497curlhelp_ssl_library
2498curlhelp_get_ssl_library ()
2499{
2500 curl_version_info_data* version_data;
2501 char *ssl_version;
2502 char *library;
2503 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2504
2505 version_data = curl_version_info (CURLVERSION_NOW);
2506 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN;
2507
2508 ssl_version = strdup (version_data->ssl_version);
2509 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN;
2510
2511 library = strtok (ssl_version, "/");
2512 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN;
2513
2514 if (strcmp (library, "OpenSSL") == 0)
2515 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2516 else if (strcmp (library, "LibreSSL") == 0)
2517 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2518 else if (strcmp (library, "GnuTLS") == 0)
2519 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2520 else if (strcmp (library, "NSS") == 0)
2521 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2522
2523 if (verbose >= 2)
2524 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2525
2526 free (ssl_version);
2527
2528 return ssl_library;
2529}
2530
2531const char*
2532curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library)
2533{
2534 switch (ssl_library) {
2535 case CURLHELP_SSL_LIBRARY_OPENSSL:
2536 return "OpenSSL";
2537 case CURLHELP_SSL_LIBRARY_LIBRESSL:
2538 return "LibreSSL";
2539 case CURLHELP_SSL_LIBRARY_GNUTLS:
2540 return "GnuTLS";
2541 case CURLHELP_SSL_LIBRARY_NSS:
2542 return "NSS";
2543 case CURLHELP_SSL_LIBRARY_UNKNOWN:
2544 default:
2545 return "unknown";
2546 }
2547}
2548
2549#ifdef LIBCURL_FEATURE_SSL
2550#ifndef USE_OPENSSL
2551time_t
2552parse_cert_date (const char *s)
2553{
2554 struct tm tm;
2555 time_t date;
2556 char *res;
2557
2558 if (!s) return -1;
2559
2560 /* Jan 17 14:25:12 2020 GMT */
2561 res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2562 /* Sep 11 12:00:00 2020 GMT */
2563 if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm);
2564 date = mktime (&tm);
2565
2566 return date;
2567}
2568
2569/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2570 * OpenSSL could be this function
2571 */
2572int
2573net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit)
2574{
2575 int i;
2576 struct curl_slist* slist;
2577 int cname_found = 0;
2578 char* start_date_str = NULL;
2579 char* end_date_str = NULL;
2580 time_t start_date;
2581 time_t end_date;
2582 char *tz;
2583 float time_left;
2584 int days_left;
2585 int time_remaining;
2586 char timestamp[50] = "";
2587 int status = STATE_UNKNOWN;
2588
2589 if (verbose >= 2)
2590 printf ("**** REQUEST CERTIFICATES ****\n");
2591
2592 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2593 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2594 /* find first common name in subject,
2595 * TODO: check alternative subjects for
2596 * TODO: have a decent parser here and not a hack
2597 * multi-host certificate, check wildcards
2598 */
2599 if (strncasecmp (slist->data, "Subject:", 8) == 0) {
2600 int d = 3;
2601 char* p = strstr (slist->data, "CN=");
2602 if (p == NULL) {
2603 d = 5;
2604 p = strstr (slist->data, "CN = ");
2605 }
2606 if (p != NULL) {
2607 if (strncmp (host_name, p+d, strlen (host_name)) == 0) {
2608 cname_found = 1;
2609 }
2610 }
2611 } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) {
2612 start_date_str = &slist->data[11];
2613 } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) {
2614 end_date_str = &slist->data[12];
2615 } else if (strncasecmp (slist->data, "Cert:", 5) == 0) {
2616 goto HAVE_FIRST_CERT;
2617 }
2618 if (verbose >= 2)
2619 printf ("%d ** %s\n", i, slist->data);
2620 }
2621 }
2622HAVE_FIRST_CERT:
2623
2624 if (verbose >= 2)
2625 printf ("**** REQUEST CERTIFICATES ****\n");
2626
2627 if (!cname_found) {
2628 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject."));
2629 return STATE_CRITICAL;
2630 }
2631
2632 start_date = parse_cert_date (start_date_str);
2633 if (start_date <= 0) {
2634 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"),
2635 start_date_str);
2636 puts (msg);
2637 return STATE_WARNING;
2638 }
2639
2640 end_date = parse_cert_date (end_date_str);
2641 if (end_date <= 0) {
2642 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"),
2643 start_date_str);
2644 puts (msg);
2645 return STATE_WARNING;
2646 }
2647
2648 time_left = difftime (end_date, time(NULL));
2649 days_left = time_left / 86400;
2650 tz = getenv("TZ");
2651 setenv("TZ", "GMT", 1);
2652 tzset();
2653 strftime(timestamp, 50, "%c %z", localtime(&end_date));
2654 if (tz)
2655 setenv("TZ", tz, 1);
2656 else
2657 unsetenv("TZ");
2658 tzset();
2659
2660 if (days_left > 0 && days_left <= days_till_exp_warn) {
2661 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, days_left, timestamp);
2662 if (days_left > days_till_exp_crit)
2663 status = STATE_WARNING;
2664 else
2665 status = STATE_CRITICAL;
2666 } else if (days_left == 0 && time_left > 0) {
2667 if (time_left >= 3600)
2668 time_remaining = (int) time_left / 3600;
2669 else
2670 time_remaining = (int) time_left / 60;
2671
2672 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"),
2673 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining,
2674 time_left >= 3600 ? "hours" : "minutes", timestamp);
2675
2676 if ( days_left > days_till_exp_crit)
2677 status = STATE_WARNING;
2678 else
2679 status = STATE_CRITICAL;
2680 } else if (time_left < 0) {
2681 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2682 status=STATE_CRITICAL;
2683 } else if (days_left == 0) {
2684 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, timestamp);
2685 if (days_left > days_till_exp_crit)
2686 status = STATE_WARNING;
2687 else
2688 status = STATE_CRITICAL;
2689 } else {
2690 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp);
2691 status = STATE_OK;
2692 }
2693 return status;
2694}
2695#endif /* USE_OPENSSL */
2696#endif /* LIBCURL_FEATURE_SSL */
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 826eb8d..c24ca24 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -35,6 +35,7 @@ const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "utils_cmd.h"
38 39
39#include "netutils.h" 40#include "netutils.h"
40 41
@@ -140,21 +141,28 @@ main (int argc, char **argv)
140 if (verbose > 2) 141 if (verbose > 2)
141 printf ("Initializing DBI\n"); 142 printf ("Initializing DBI\n");
142 143
143 if (dbi_initialize (NULL) < 0) { 144 dbi_inst *instance_p;
145
146 if (dbi_initialize_r(NULL, instance_p) < 0) {
144 printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); 147 printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
145 return STATE_UNKNOWN; 148 return STATE_UNKNOWN;
146 } 149 }
147 150
151 if (instance_p == NULL) {
152 printf ("UNKNOWN - failed to initialize DBI.\n");
153 return STATE_UNKNOWN;
154 }
155
148 if (verbose) 156 if (verbose)
149 printf ("Opening DBI driver '%s'\n", np_dbi_driver); 157 printf ("Opening DBI driver '%s'\n", np_dbi_driver);
150 158
151 driver = dbi_driver_open (np_dbi_driver); 159 driver = dbi_driver_open_r(np_dbi_driver, instance_p);
152 if (! driver) { 160 if (! driver) {
153 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", 161 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
154 np_dbi_driver); 162 np_dbi_driver);
155 163
156 printf ("Known drivers:\n"); 164 printf ("Known drivers:\n");
157 for (driver = dbi_driver_list (NULL); driver; driver = dbi_driver_list (driver)) { 165 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
158 printf (" - %s\n", dbi_driver_get_name (driver)); 166 printf (" - %s\n", dbi_driver_get_name (driver));
159 } 167 }
160 return STATE_UNKNOWN; 168 return STATE_UNKNOWN;
@@ -425,6 +433,7 @@ process_arguments (int argc, char **argv)
425 else 433 else
426 timeout_interval = atoi (optarg); 434 timeout_interval = atoi (optarg);
427 435
436 break;
428 case 'H': /* host */ 437 case 'H': /* host */
429 if (!is_host (optarg)) 438 if (!is_host (optarg))
430 usage2 (_("Invalid hostname/address"), optarg); 439 usage2 (_("Invalid hostname/address"), optarg);
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index e73a008..7dc1c4b 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -1,29 +1,29 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_disk plugin 3* Monitoring check_disk plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 1999-2008 Monitoring Plugins Development Team 6* Copyright (c) 1999-2008 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
10* This file contains the check_disk plugin 10* This file contains the check_disk plugin
11* 11*
12* 12*
13* This program is free software: you can redistribute it and/or modify 13* This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14* it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15* the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16* (at your option) any later version.
17* 17*
18* This program is distributed in the hope that it will be useful, 18* This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19* but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21* GNU General Public License for more details.
22* 22*
23* You should have received a copy of the GNU General Public License 23* You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24* along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25*
26* 26*
27*****************************************************************************/ 27*****************************************************************************/
28 28
29const char *progname = "check_disk"; 29const char *progname = "check_disk";
@@ -46,7 +46,7 @@ const char *email = "devel@monitoring-plugins.org";
46#include <stdarg.h> 46#include <stdarg.h>
47#include "fsusage.h" 47#include "fsusage.h"
48#include "mountlist.h" 48#include "mountlist.h"
49#include "intprops.h" /* necessary for TYPE_MAXIMUM */ 49#include "intprops.h" /* necessary for TYPE_MAXIMUM */
50#if HAVE_LIMITS_H 50#if HAVE_LIMITS_H
51# include <limits.h> 51# include <limits.h>
52#endif 52#endif
@@ -112,11 +112,12 @@ enum
112{ 112{
113 SYNC_OPTION = CHAR_MAX + 1, 113 SYNC_OPTION = CHAR_MAX + 1,
114 NO_SYNC_OPTION, 114 NO_SYNC_OPTION,
115 BLOCK_SIZE_OPTION 115 BLOCK_SIZE_OPTION,
116 IGNORE_MISSING
116}; 117};
117 118
118#ifdef _AIX 119#ifdef _AIX
119 #pragma alloca 120#pragma alloca
120#endif 121#endif
121 122
122int process_arguments (int, char **); 123int process_arguments (int, char **);
@@ -126,13 +127,10 @@ int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, ch
126void print_help (void); 127void print_help (void);
127void print_usage (void); 128void print_usage (void);
128double calculate_percent(uintmax_t, uintmax_t); 129double calculate_percent(uintmax_t, uintmax_t);
129void stat_path (struct parameter_list *p); 130bool stat_path (struct parameter_list *p);
130void get_stats (struct parameter_list *p, struct fs_usage *fsp); 131void get_stats (struct parameter_list *p, struct fs_usage *fsp);
131void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); 132void get_path_stats (struct parameter_list *p, struct fs_usage *fsp);
132 133
133double w_dfp = -1.0;
134double c_dfp = -1.0;
135char *path;
136char *exclude_device; 134char *exclude_device;
137char *units; 135char *units;
138uintmax_t mult = 1024 * 1024; 136uintmax_t mult = 1024 * 1024;
@@ -140,7 +138,9 @@ int verbose = 0;
140int erronly = FALSE; 138int erronly = FALSE;
141int display_mntp = FALSE; 139int display_mntp = FALSE;
142int exact_match = FALSE; 140int exact_match = FALSE;
141bool ignore_missing = false;
143int freespace_ignore_reserved = FALSE; 142int freespace_ignore_reserved = FALSE;
143int display_inodes_perfdata = FALSE;
144char *warn_freespace_units = NULL; 144char *warn_freespace_units = NULL;
145char *crit_freespace_units = NULL; 145char *crit_freespace_units = NULL;
146char *warn_freespace_percent = NULL; 146char *warn_freespace_percent = NULL;
@@ -154,6 +154,7 @@ char *crit_usedinodes_percent = NULL;
154char *warn_freeinodes_percent = NULL; 154char *warn_freeinodes_percent = NULL;
155char *crit_freeinodes_percent = NULL; 155char *crit_freeinodes_percent = NULL;
156int path_selected = FALSE; 156int path_selected = FALSE;
157bool path_ignored = false;
157char *group = NULL; 158char *group = NULL;
158struct stat *stat_buf; 159struct stat *stat_buf;
159struct name_list *seen = NULL; 160struct name_list *seen = NULL;
@@ -165,13 +166,13 @@ main (int argc, char **argv)
165 int result = STATE_UNKNOWN; 166 int result = STATE_UNKNOWN;
166 int disk_result = STATE_UNKNOWN; 167 int disk_result = STATE_UNKNOWN;
167 char *output; 168 char *output;
169 char *ignored;
168 char *details; 170 char *details;
169 char *perf; 171 char *perf;
170 char *preamble; 172 char *perf_ilabel;
173 char *preamble = " - free space:";
174 char *ignored_preamble = " - ignored paths:";
171 char *flag_header; 175 char *flag_header;
172 double inode_space_pct;
173 double warning_high_tide;
174 double critical_high_tide;
175 int temp_result; 176 int temp_result;
176 177
177 struct mount_entry *me; 178 struct mount_entry *me;
@@ -182,10 +183,11 @@ main (int argc, char **argv)
182 char mountdir[32]; 183 char mountdir[32];
183#endif 184#endif
184 185
185 preamble = strdup (" - free space:");
186 output = strdup (""); 186 output = strdup ("");
187 ignored = strdup ("");
187 details = strdup (""); 188 details = strdup ("");
188 perf = strdup (""); 189 perf = strdup ("");
190 perf_ilabel = strdup ("");
189 stat_buf = malloc(sizeof *stat_buf); 191 stat_buf = malloc(sizeof *stat_buf);
190 192
191 setlocale (LC_ALL, ""); 193 setlocale (LC_ALL, "");
@@ -203,7 +205,7 @@ main (int argc, char **argv)
203 /* If a list of paths has not been selected, find entire 205 /* If a list of paths has not been selected, find entire
204 mount list and create list of paths 206 mount list and create list of paths
205 */ 207 */
206 if (path_selected == FALSE) { 208 if (path_selected == FALSE && path_ignored == false) {
207 for (me = mount_list; me; me = me->me_next) { 209 for (me = mount_list; me; me = me->me_next) {
208 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) { 210 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
209 path = np_add_parameter(&path_select_list, me->me_mountdir); 211 path = np_add_parameter(&path_select_list, me->me_mountdir);
@@ -213,24 +215,49 @@ main (int argc, char **argv)
213 set_all_thresholds(path); 215 set_all_thresholds(path);
214 } 216 }
215 } 217 }
216 np_set_best_match(path_select_list, mount_list, exact_match); 218
219 if (path_ignored == false) {
220 np_set_best_match(path_select_list, mount_list, exact_match);
221 }
217 222
218 /* Error if no match found for specified paths */ 223 /* Error if no match found for specified paths */
219 temp_list = path_select_list; 224 temp_list = path_select_list;
220 225
221 while (temp_list) { 226 while (path_select_list) {
222 if (! temp_list->best_match) { 227 if (! path_select_list->best_match && ignore_missing == true) {
223 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name); 228 /* If the first element will be deleted, the temp_list must be updated with the new start address as well */
229 if (path_select_list == temp_list) {
230 temp_list = path_select_list->name_next;
231 }
232 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
233 xasprintf (&ignored, "%s %s;", ignored, path_select_list->name);
234 /* Delete the path from the list so that it is not stat-checked later in the code. */
235 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
236 } else if (! path_select_list->best_match) {
237 /* Without --ignore-missing option, exit with Critical state. */
238 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
239 } else {
240 /* Continue jumping through the list */
241 path_select_list = path_select_list->name_next;
224 } 242 }
243 }
244
245 path_select_list = temp_list;
225 246
226 temp_list = temp_list->name_next; 247 if (! path_select_list && ignore_missing == true) {
248 result = STATE_OK;
249 if (verbose >= 2) {
250 printf ("None of the provided paths were found\n");
251 }
227 } 252 }
228 253
229 /* Process for every path in list */ 254 /* Process for every path in list */
230 for (path = path_select_list; path; path=path->name_next) { 255 for (path = path_select_list; path; path=path->name_next) {
231 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL) 256 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
232 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end, 257 printf("Thresholds(pct) for %s warn: %f crit %f\n",
233 path->freespace_percent->critical->end); 258 path->name,
259 path->freespace_percent->warning->end,
260 path->freespace_percent->critical->end);
234 261
235 if (verbose >= 3 && path->group != NULL) 262 if (verbose >= 3 && path->group != NULL)
236 printf("Group of %s: %s\n",path->name,path->group); 263 printf("Group of %s: %s\n",path->name,path->group);
@@ -240,26 +267,34 @@ main (int argc, char **argv)
240 267
241 me = path->best_match; 268 me = path->best_match;
242 269
270 if (!me) {
271 continue;
272 }
273
243#ifdef __CYGWIN__ 274#ifdef __CYGWIN__
244 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 275 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11)
245 continue; 276 continue;
246 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 277 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
247 if (GetDriveType(mountdir) != DRIVE_FIXED) 278 if (GetDriveType(mountdir) != DRIVE_FIXED)
248 me->me_remote = 1; 279 me->me_remote = 1;
249#endif 280#endif
250 /* Filters */ 281 /* Filters */
251 282
252 /* Remove filesystems already seen */ 283 /* Remove filesystems already seen */
253 if (np_seen_name(seen, me->me_mountdir)) { 284 if (np_seen_name(seen, me->me_mountdir)) {
254 continue; 285 continue;
255 } 286 }
256 np_add_name(&seen, me->me_mountdir); 287 np_add_name(&seen, me->me_mountdir);
257 288
258 if (path->group == NULL) { 289 if (path->group == NULL) {
259 /* Skip remote filesystems if we're not interested in them */ 290 /* Skip remote filesystems if we're not interested in them */
260 if (me->me_remote && show_local_fs) { 291 if (me->me_remote && show_local_fs) {
261 if (stat_remote_fs) 292 if (stat_remote_fs) {
262 stat_path(path); 293 if (!stat_path(path) && ignore_missing == true) {
294 result = STATE_OK;
295 xasprintf (&ignored, "%s %s;", ignored, path->name);
296 }
297 }
263 continue; 298 continue;
264 /* Skip pseudo fs's if we haven't asked for all fs's */ 299 /* Skip pseudo fs's if we haven't asked for all fs's */
265 } else if (me->me_dummy && !show_all_fs) { 300 } else if (me->me_dummy && !show_all_fs) {
@@ -278,15 +313,30 @@ main (int argc, char **argv)
278 } 313 }
279 } 314 }
280 315
281 stat_path(path); 316 if (!stat_path(path)) {
317 if (ignore_missing == true) {
318 result = STATE_OK;
319 xasprintf (&ignored, "%s %s;", ignored, path->name);
320 }
321 continue;
322 }
282 get_fs_usage (me->me_mountdir, me->me_devname, &fsp); 323 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
283 324
284 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) { 325 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
285 get_stats (path, &fsp); 326 get_stats (path, &fsp);
286 327
287 if (verbose >= 3) { 328 if (verbose >= 3) {
288 printf ("For %s, used_pct=%g free_pct=%g used_units=%g free_units=%g total_units=%g used_inodes_pct=%g free_inodes_pct=%g fsp.fsu_blocksize=%llu mult=%llu\n", 329 printf ("For %s, used_pct=%g free_pct=%g used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%g free_inodes_pct=%g fsp.fsu_blocksize=%lu mult=%lu\n",
289 me->me_mountdir, path->dused_pct, path->dfree_pct, path->dused_units, path->dfree_units, path->dtotal_units, path->dused_inodes_percent, path->dfree_inodes_percent, fsp.fsu_blocksize, mult); 330 me->me_mountdir,
331 path->dused_pct,
332 path->dfree_pct,
333 path->dused_units,
334 path->dfree_units,
335 path->dtotal_units,
336 path->dused_inodes_percent,
337 path->dfree_inodes_percent,
338 fsp.fsu_blocksize,
339 mult);
290 } 340 }
291 341
292 /* Threshold comparisons */ 342 /* Threshold comparisons */
@@ -323,68 +373,89 @@ main (int argc, char **argv)
323 */ 373 */
324 374
325 /* *_high_tide must be reinitialized at each run */ 375 /* *_high_tide must be reinitialized at each run */
326 warning_high_tide = UINT_MAX; 376 uint64_t warning_high_tide = UINT64_MAX;
327 critical_high_tide = UINT_MAX;
328 377
329 if (path->freespace_units->warning != NULL) { 378 if (path->freespace_units->warning != NULL) {
330 warning_high_tide = path->dtotal_units - path->freespace_units->warning->end; 379 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
331 } 380 }
332 if (path->freespace_percent->warning != NULL) { 381 if (path->freespace_percent->warning != NULL) {
333 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*path->dtotal_units )); 382 warning_high_tide = min( warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end/100) * (path->dtotal_units * mult)) );
334 } 383 }
384
385 uint64_t critical_high_tide = UINT64_MAX;
386
335 if (path->freespace_units->critical != NULL) { 387 if (path->freespace_units->critical != NULL) {
336 critical_high_tide = path->dtotal_units - path->freespace_units->critical->end; 388 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
337 } 389 }
338 if (path->freespace_percent->critical != NULL) { 390 if (path->freespace_percent->critical != NULL) {
339 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*path->dtotal_units )); 391 critical_high_tide = min( critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end/100) * (path->dtotal_units * mult)) );
340 } 392 }
341 393
342 /* Nb: *_high_tide are unset when == UINT_MAX */ 394 /* Nb: *_high_tide are unset when == UINT64_MAX */
343 xasprintf (&perf, "%s %s", perf, 395 xasprintf (&perf, "%s %s", perf,
344 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, 396 perfdata_uint64 (
345 path->dused_units, units, 397 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
346 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide, 398 path->dused_units * mult, "B",
347 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide, 399 (warning_high_tide == UINT64_MAX ? FALSE : TRUE), warning_high_tide,
348 TRUE, 0, 400 (critical_high_tide == UINT64_MAX ? FALSE : TRUE), critical_high_tide,
349 TRUE, path->dtotal_units)); 401 TRUE, 0,
402 TRUE, path->dtotal_units * mult));
403
404 if (display_inodes_perfdata) {
405 /* *_high_tide must be reinitialized at each run */
406 warning_high_tide = UINT64_MAX;
407 critical_high_tide = UINT64_MAX;
408
409 if (path->freeinodes_percent->warning != NULL) {
410 warning_high_tide = (uint64_t) fabs( min( (double) warning_high_tide, (double) (1.0 - path->freeinodes_percent->warning->end/100)*path->inodes_total ));
411 }
412 if (path->freeinodes_percent->critical != NULL) {
413 critical_high_tide = (uint64_t) fabs( min( (double) critical_high_tide, (double) (1.0 - path->freeinodes_percent->critical->end/100)*path->inodes_total ));
414 }
415
416 xasprintf (&perf_ilabel, "%s (inodes)", (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
417 /* Nb: *_high_tide are unset when == UINT64_MAX */
418 xasprintf (&perf, "%s %s", perf,
419 perfdata_uint64 (perf_ilabel,
420 path->inodes_used, "",
421 (warning_high_tide != UINT64_MAX ? TRUE : FALSE), warning_high_tide,
422 (critical_high_tide != UINT64_MAX ? TRUE : FALSE), critical_high_tide,
423 TRUE, 0,
424 TRUE, path->inodes_total));
425 }
350 426
351 if (disk_result==STATE_OK && erronly && !verbose) 427 if (disk_result==STATE_OK && erronly && !verbose)
352 continue; 428 continue;
353 429
354 if(disk_result && verbose >= 1) { 430 if(disk_result && verbose >= 1) {
355 xasprintf(&flag_header, " %s [", state_text (disk_result)); 431 xasprintf(&flag_header, " %s [", state_text (disk_result));
356 } else { 432 } else {
357 xasprintf(&flag_header, ""); 433 xasprintf(&flag_header, "");
358 } 434 }
359 xasprintf (&output, "%s%s %s %.0f %s (%.0f%%", 435 xasprintf (&output, "%s%s %s %llu%s (%.0f%%",
360 output, flag_header, 436 output, flag_header,
361 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, 437 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
362 path->dfree_units, 438 path->dfree_units,
363 units, 439 units,
364 path->dfree_pct); 440 path->dfree_pct);
365 if (path->dused_inodes_percent < 0) { 441 if (path->dused_inodes_percent < 0) {
366 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : "")); 442 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
367 } else { 443 } else {
368 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : "")); 444 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
369 } 445 }
370 free(flag_header); 446 free(flag_header);
371 /* TODO: Need to do a similar debug line
372 xasprintf (&details, _("%s\n\
373%.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
374 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
375 me->me_devname, me->me_type, me->me_mountdir,
376 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
377 */
378
379 } 447 }
380
381 } 448 }
382 449
383 if (verbose >= 2) 450 if (verbose >= 2)
384 xasprintf (&output, "%s%s", output, details); 451 xasprintf (&output, "%s%s", output, details);
385 452
453 if (strcmp(output, "") == 0 && ! erronly) {
454 preamble = "";
455 xasprintf (&output, " - No disks were found for provided parameters;");
456 }
386 457
387 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf); 458 printf ("DISK %s%s%s%s%s|%s\n", state_text (result), ((erronly && result==STATE_OK)) ? "" : preamble, output, (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
388 return result; 459 return result;
389} 460}
390 461
@@ -453,8 +524,10 @@ process_arguments (int argc, char **argv)
453 {"ignore-ereg-partition", required_argument, 0, 'i'}, 524 {"ignore-ereg-partition", required_argument, 0, 'i'},
454 {"ignore-eregi-path", required_argument, 0, 'I'}, 525 {"ignore-eregi-path", required_argument, 0, 'I'},
455 {"ignore-eregi-partition", required_argument, 0, 'I'}, 526 {"ignore-eregi-partition", required_argument, 0, 'I'},
527 {"ignore-missing", no_argument, 0, IGNORE_MISSING},
456 {"local", no_argument, 0, 'l'}, 528 {"local", no_argument, 0, 'l'},
457 {"stat-remote-fs", no_argument, 0, 'L'}, 529 {"stat-remote-fs", no_argument, 0, 'L'},
530 {"iperfdata", no_argument, 0, 'P'},
458 {"mountpoint", no_argument, 0, 'M'}, 531 {"mountpoint", no_argument, 0, 'M'},
459 {"errors-only", no_argument, 0, 'e'}, 532 {"errors-only", no_argument, 0, 'e'},
460 {"exact-match", no_argument, 0, 'E'}, 533 {"exact-match", no_argument, 0, 'E'},
@@ -477,7 +550,7 @@ process_arguments (int argc, char **argv)
477 strcpy (argv[c], "-t"); 550 strcpy (argv[c], "-t");
478 551
479 while (1) { 552 while (1) {
480 c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLg:R:r:i:I:MEA", longopts, &option); 553 c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEA", longopts, &option);
481 554
482 if (c == -1 || c == EOF) 555 if (c == -1 || c == EOF)
483 break; 556 break;
@@ -511,7 +584,7 @@ process_arguments (int argc, char **argv)
511 584
512 /* Awful mistake where the range values do not make sense. Normally, 585 /* Awful mistake where the range values do not make sense. Normally,
513 you alert if the value is within the range, but since we are using 586 you alert if the value is within the range, but since we are using
514 freespace, we have to alert if outside the range. Thus we artifically 587 freespace, we have to alert if outside the range. Thus we artificially
515 force @ at the beginning of the range, so that it is backwards compatible 588 force @ at the beginning of the range, so that it is backwards compatible
516 */ 589 */
517 case 'c': /* critical threshold */ 590 case 'c': /* critical threshold */
@@ -530,14 +603,14 @@ process_arguments (int argc, char **argv)
530 } 603 }
531 break; 604 break;
532 605
533 case 'W': /* warning inode threshold */ 606 case 'W': /* warning inode threshold */
534 if (*optarg == '@') { 607 if (*optarg == '@') {
535 warn_freeinodes_percent = optarg; 608 warn_freeinodes_percent = optarg;
536 } else { 609 } else {
537 xasprintf(&warn_freeinodes_percent, "@%s", optarg); 610 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
538 } 611 }
539 break; 612 break;
540 case 'K': /* critical inode threshold */ 613 case 'K': /* critical inode threshold */
541 if (*optarg == '@') { 614 if (*optarg == '@') {
542 crit_freeinodes_percent = optarg; 615 crit_freeinodes_percent = optarg;
543 } else { 616 } else {
@@ -547,21 +620,39 @@ process_arguments (int argc, char **argv)
547 case 'u': 620 case 'u':
548 if (units) 621 if (units)
549 free(units); 622 free(units);
550 if (! strcmp (optarg, "bytes")) { 623 if (! strcasecmp (optarg, "bytes")) {
551 mult = (uintmax_t)1; 624 mult = (uintmax_t)1;
552 units = strdup ("B"); 625 units = strdup ("B");
553 } else if (! strcmp (optarg, "kB")) { 626 } else if (!strcmp(optarg, "KiB")) {
554 mult = (uintmax_t)1024; 627 mult = (uintmax_t)1024;
628 units = strdup ("KiB");
629 } else if (! strcmp (optarg, "kB")) {
630 mult = (uintmax_t)1000;
555 units = strdup ("kB"); 631 units = strdup ("kB");
556 } else if (! strcmp (optarg, "MB")) { 632 } else if (!strcmp(optarg, "MiB")) {
557 mult = (uintmax_t)1024 * 1024; 633 mult = (uintmax_t)1024 * 1024;
634 units = strdup ("MiB");
635 } else if (! strcmp (optarg, "MB")) {
636 mult = (uintmax_t)1000 * 1000;
558 units = strdup ("MB"); 637 units = strdup ("MB");
559 } else if (! strcmp (optarg, "GB")) { 638 } else if (!strcmp(optarg, "GiB")) {
560 mult = (uintmax_t)1024 * 1024 * 1024; 639 mult = (uintmax_t)1024 * 1024 * 1024;
640 units = strdup ("GiB");
641 } else if (! strcmp (optarg, "GB")){
642 mult = (uintmax_t)1000 * 1000 * 1000;
561 units = strdup ("GB"); 643 units = strdup ("GB");
562 } else if (! strcmp (optarg, "TB")) { 644 } else if (!strcmp(optarg, "TiB")) {
563 mult = (uintmax_t)1024 * 1024 * 1024 * 1024; 645 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
646 units = strdup ("TiB");
647 } else if (! strcmp (optarg, "TB")) {
648 mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
564 units = strdup ("TB"); 649 units = strdup ("TB");
650 } else if (!strcmp(optarg, "PiB")) {
651 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
652 units = strdup ("PiB");
653 } else if (! strcmp (optarg, "PB")){
654 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
655 units = strdup ("PB");
565 } else { 656 } else {
566 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg); 657 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
567 } 658 }
@@ -572,19 +663,23 @@ process_arguments (int argc, char **argv)
572 mult = 1024; 663 mult = 1024;
573 if (units) 664 if (units)
574 free(units); 665 free(units);
575 units = strdup ("kB"); 666 units = strdup ("kiB");
576 break; 667 break;
577 case 'm': /* display mountpoint */ 668 case 'm': /* display mountpoint */
578 mult = 1024 * 1024; 669 mult = 1024 * 1024;
579 if (units) 670 if (units)
580 free(units); 671 free(units);
581 units = strdup ("MB"); 672 units = strdup ("MiB");
582 break; 673 break;
583 case 'L': 674 case 'L':
584 stat_remote_fs = 1; 675 stat_remote_fs = 1;
676 /* fallthrough */
585 case 'l': 677 case 'l':
586 show_local_fs = 1; 678 show_local_fs = 1;
587 break; 679 break;
680 case 'P':
681 display_inodes_perfdata = 1;
682 break;
588 case 'p': /* select path */ 683 case 'p': /* select path */
589 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 684 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
590 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units || 685 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
@@ -596,12 +691,19 @@ process_arguments (int argc, char **argv)
596 /* add parameter if not found. overwrite thresholds if path has already been added */ 691 /* add parameter if not found. overwrite thresholds if path has already been added */
597 if (! (se = np_find_parameter(path_select_list, optarg))) { 692 if (! (se = np_find_parameter(path_select_list, optarg))) {
598 se = np_add_parameter(&path_select_list, optarg); 693 se = np_add_parameter(&path_select_list, optarg);
694
695 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
696 path_ignored = true;
697 break;
698 }
599 } 699 }
600 se->group = group; 700 se->group = group;
601 set_all_thresholds(se); 701 set_all_thresholds(se);
602 702
603 /* With autofs, it is required to stat() the path before re-populating the mount_list */ 703 /* With autofs, it is required to stat() the path before re-populating the mount_list */
604 stat_path(se); 704 if (!stat_path(se)) {
705 break;
706 }
605 /* NB: We can't free the old mount_list "just like that": both list pointers and struct 707 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
606 * pointers are copied around. One of the reason it wasn't done yet is that other parts 708 * pointers are copied around. One of the reason it wasn't done yet is that other parts
607 * of check_disk need the same kind of cleanup so it'd better be done as a whole */ 709 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
@@ -644,6 +746,7 @@ process_arguments (int argc, char **argv)
644 break; 746 break;
645 case 'I': 747 case 'I':
646 cflags |= REG_ICASE; 748 cflags |= REG_ICASE;
749 // Intentional fallthrough
647 case 'i': 750 case 'i':
648 if (!path_selected) 751 if (!path_selected)
649 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly")); 752 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
@@ -681,16 +784,21 @@ process_arguments (int argc, char **argv)
681 cflags = default_cflags; 784 cflags = default_cflags;
682 break; 785 break;
683 786
787 case IGNORE_MISSING:
788 ignore_missing = true;
789 break;
684 case 'A': 790 case 'A':
685 optarg = strdup(".*"); 791 optarg = strdup(".*");
792 // Intentional fallthrough
686 case 'R': 793 case 'R':
687 cflags |= REG_ICASE; 794 cflags |= REG_ICASE;
795 // Intentional fallthrough
688 case 'r': 796 case 'r':
689 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 797 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
690 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units || 798 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
691 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent || 799 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
692 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) { 800 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
693 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n")); 801 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
694 } 802 }
695 803
696 err = regcomp(&re, optarg, cflags); 804 err = regcomp(&re, optarg, cflags);
@@ -714,7 +822,11 @@ process_arguments (int argc, char **argv)
714 } 822 }
715 } 823 }
716 824
717 if (!fnd) 825 if (!fnd && ignore_missing == true) {
826 path_ignored = true;
827 /* path_selected = TRUE;*/
828 break;
829 } else if (!fnd)
718 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), 830 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
719 _("Regular expression did not match any path or disk"), optarg); 831 _("Regular expression did not match any path or disk"), optarg);
720 832
@@ -774,14 +886,14 @@ process_arguments (int argc, char **argv)
774 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c])) 886 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
775 crit_usedspace_percent = argv[c++]; 887 crit_usedspace_percent = argv[c++];
776 888
777 if (argc > c && path == NULL) { 889 if (argc > c) {
778 se = np_add_parameter(&path_select_list, strdup(argv[c++])); 890 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
779 path_selected = TRUE; 891 path_selected = TRUE;
780 set_all_thresholds(se); 892 set_all_thresholds(se);
781 } 893 }
782 894
783 if (units == NULL) { 895 if (units == NULL) {
784 units = strdup ("MB"); 896 units = strdup ("MiB");
785 mult = (uintmax_t)1024 * 1024; 897 mult = (uintmax_t)1024 * 1024;
786 } 898 }
787 899
@@ -817,51 +929,6 @@ set_all_thresholds (struct parameter_list *path)
817 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); 929 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
818} 930}
819 931
820/* TODO: Remove?
821
822int
823validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
824{
825 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
826 printf (_("INPUT ERROR: No thresholds specified"));
827 print_path (mypath);
828 return ERROR;
829 }
830 else if ((wp >= 0.0 || cp >= 0.0) &&
831 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
832 printf (_("\
833INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
834 cp, wp);
835 print_path (mypath);
836 return ERROR;
837 }
838 else if ((iwp >= 0.0 || icp >= 0.0) &&
839 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
840 printf (_("\
841INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
842 icp, iwp);
843 print_path (mypath);
844 return ERROR;
845 }
846 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
847 printf (_("\
848INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
849 (unsigned long)c, (unsigned long)w);
850 print_path (mypath);
851 return ERROR;
852 }
853
854 return OK;
855}
856
857*/
858
859
860
861
862
863
864
865void 932void
866print_help (void) 933print_help (void)
867{ 934{
@@ -904,6 +971,8 @@ print_help (void)
904 printf (" %s\n", _("Display only devices/mountpoints with errors")); 971 printf (" %s\n", _("Display only devices/mountpoints with errors"));
905 printf (" %s\n", "-f, --freespace-ignore-reserved"); 972 printf (" %s\n", "-f, --freespace-ignore-reserved");
906 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata")); 973 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
974 printf (" %s\n", "-P, --iperfdata");
975 printf (" %s\n", _("Display inode usage in perfdata"));
907 printf (" %s\n", "-g, --group=NAME"); 976 printf (" %s\n", "-g, --group=NAME");
908 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together")); 977 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
909 printf (" %s\n", "-k, --kilobytes"); 978 printf (" %s\n", "-k, --kilobytes");
@@ -914,7 +983,7 @@ print_help (void)
914 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems")); 983 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
915 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)")); 984 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
916 printf (" %s\n", "-M, --mountpoint"); 985 printf (" %s\n", "-M, --mountpoint");
917 printf (" %s\n", _("Display the mountpoint instead of the partition")); 986 printf (" %s\n", _("Display the (block) device instead of the mount point"));
918 printf (" %s\n", "-m, --megabytes"); 987 printf (" %s\n", "-m, --megabytes");
919 printf (" %s\n", _("Same as '--units MB'")); 988 printf (" %s\n", _("Same as '--units MB'"));
920 printf (" %s\n", "-A, --all"); 989 printf (" %s\n", "-A, --all");
@@ -927,6 +996,9 @@ print_help (void)
927 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)")); 996 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
928 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION"); 997 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
929 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)")); 998 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
999 printf (" %s\n", "--ignore-missing");
1000 printf (" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
1001 printf (" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
930 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1002 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
931 printf (" %s\n", "-u, --units=STRING"); 1003 printf (" %s\n", "-u, --units=STRING");
932 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)")); 1004 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
@@ -937,12 +1009,20 @@ print_help (void)
937 printf (" %s\n", _("Check only filesystems of indicated type (may be repeated)")); 1009 printf (" %s\n", _("Check only filesystems of indicated type (may be repeated)"));
938 1010
939 printf ("\n"); 1011 printf ("\n");
1012 printf ("%s\n", _("General usage hints:"));
1013 printf (" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1014 printf (" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1015 printf (" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1016
1017
1018
1019 printf ("\n");
940 printf ("%s\n", _("Examples:")); 1020 printf ("%s\n", _("Examples:"));
941 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /"); 1021 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
942 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB")); 1022 printf (" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
943 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'"); 1023 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
944 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex")); 1024 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
945 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together")); 1025 printf (" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
946 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar"); 1026 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
947 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M")); 1027 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
948 1028
@@ -955,12 +1035,12 @@ void
955print_usage (void) 1035print_usage (void)
956{ 1036{
957 printf ("%s\n", _("Usage:")); 1037 printf ("%s\n", _("Usage:"));
958 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname); 1038 printf (" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K inode_percentage_limit } {-p path | -x device}\n", progname);
959 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 1039 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
960 printf ("[-t timeout] [-u unit] [-v] [-X type] [-N type]\n"); 1040 printf ("[-t timeout] [-u unit] [-v] [-X type] [-N type]\n");
961} 1041}
962 1042
963void 1043bool
964stat_path (struct parameter_list *p) 1044stat_path (struct parameter_list *p)
965{ 1045{
966 /* Stat entry to check that dir exists and is accessible */ 1046 /* Stat entry to check that dir exists and is accessible */
@@ -969,9 +1049,14 @@ stat_path (struct parameter_list *p)
969 if (stat (p->name, &stat_buf[0])) { 1049 if (stat (p->name, &stat_buf[0])) {
970 if (verbose >= 3) 1050 if (verbose >= 3)
971 printf("stat failed on %s\n", p->name); 1051 printf("stat failed on %s\n", p->name);
972 printf("DISK %s - ", _("CRITICAL")); 1052 if (ignore_missing == true) {
973 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 1053 return false;
1054 } else {
1055 printf("DISK %s - ", _("CRITICAL"));
1056 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
1057 }
974 } 1058 }
1059 return true;
975} 1060}
976 1061
977 1062
@@ -991,66 +1076,87 @@ get_stats (struct parameter_list *p, struct fs_usage *fsp) {
991 continue; 1076 continue;
992#endif 1077#endif
993 if (p_list->group && ! (strcmp(p_list->group, p->group))) { 1078 if (p_list->group && ! (strcmp(p_list->group, p->group))) {
994 stat_path(p_list); 1079 if (! stat_path(p_list))
1080 continue;
995 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); 1081 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp);
996 get_path_stats(p_list, &tmpfsp); 1082 get_path_stats(p_list, &tmpfsp);
997 if (verbose >= 3) 1083 if (verbose >= 3)
998 printf("Group %s: adding %llu blocks sized %llu, (%s) used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n", 1084 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n",
999 p_list->group, tmpfsp.fsu_bavail, tmpfsp.fsu_blocksize, p_list->best_match->me_mountdir, p_list->dused_units, p_list->dfree_units, 1085 p_list->group,
1000 p_list->dtotal_units, mult); 1086 tmpfsp.fsu_blocks,
1001 1087 tmpfsp.fsu_blocksize,
1002 /* prevent counting the first FS of a group twice since its parameter_list entry 1088 p_list->best_match->me_mountdir,
1089 p_list->dused_units,
1090 p_list->dfree_units,
1091 p_list->dtotal_units,
1092 mult);
1093
1094 /* prevent counting the first FS of a group twice since its parameter_list entry
1003 * is used to carry the information of all file systems of the entire group */ 1095 * is used to carry the information of all file systems of the entire group */
1004 if (! first) { 1096 if (! first) {
1005 p->total += p_list->total; 1097 p->total += p_list->total;
1006 p->available += p_list->available; 1098 p->available += p_list->available;
1007 p->available_to_root += p_list->available_to_root; 1099 p->available_to_root += p_list->available_to_root;
1008 p->used += p_list->used; 1100 p->used += p_list->used;
1009 1101
1010 p->dused_units += p_list->dused_units; 1102 p->dused_units += p_list->dused_units;
1011 p->dfree_units += p_list->dfree_units; 1103 p->dfree_units += p_list->dfree_units;
1012 p->dtotal_units += p_list->dtotal_units; 1104 p->dtotal_units += p_list->dtotal_units;
1013 p->inodes_total += p_list->inodes_total; 1105 p->inodes_total += p_list->inodes_total;
1014 p->inodes_free += p_list->inodes_free; 1106 p->inodes_free += p_list->inodes_free;
1107 p->inodes_free_to_root += p_list->inodes_free_to_root;
1108 p->inodes_used += p_list->inodes_used;
1015 } 1109 }
1016 first = 0; 1110 first = 0;
1017 } 1111 }
1018 if (verbose >= 3) 1112 if (verbose >= 3)
1019 printf("Group %s now has: used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n", 1113 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n",
1020 p->group, tmpfsp.fsu_bavail, tmpfsp.fsu_blocksize, p->best_match->me_mountdir, p->dused_units, 1114 p->group,
1021 p->dfree_units, p->dtotal_units, mult); 1115 p->dused_units,
1116 p->dfree_units,
1117 p->dtotal_units,
1118 tmpfsp.fsu_blocksize,
1119 mult);
1022 } 1120 }
1023 /* modify devname and mountdir for output */ 1121 /* modify devname and mountdir for output */
1024 p->best_match->me_mountdir = p->best_match->me_devname = p->group; 1122 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1025 } 1123 }
1026 /* finally calculate percentages for either plain FS or summed up group */ 1124 /* finally calculate percentages for either plain FS or summed up group */
1027 p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */ 1125 p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */
1028 p->dfree_pct = 100 - p->dused_pct; 1126 p->dfree_pct = 100 - p->dused_pct;
1029 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total); 1127 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1030 p->dfree_inodes_percent = 100 - p->dused_inodes_percent; 1128 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
1031 1129
1032} 1130}
1033 1131
1034void 1132void
1035get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { 1133get_path_stats (struct parameter_list *p, struct fs_usage *fsp) {
1036 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available 1134 p->available = fsp->fsu_bavail;
1037 * space on BSD (the actual value should be negative but fsp->fsu_bavail
1038 * is unsigned) */
1039 p->available = fsp->fsu_bavail > fsp->fsu_bfree ? 0 : fsp->fsu_bavail;
1040 p->available_to_root = fsp->fsu_bfree; 1135 p->available_to_root = fsp->fsu_bfree;
1041 p->used = fsp->fsu_blocks - fsp->fsu_bfree; 1136 p->used = fsp->fsu_blocks - fsp->fsu_bfree;
1042 if (freespace_ignore_reserved) { 1137 if (freespace_ignore_reserved) {
1043 /* option activated : we substract the root-reserved space from the total */ 1138 /* option activated : we subtract the root-reserved space from the total */
1044 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1139 p->total = fsp->fsu_blocks - p->available_to_root + p->available;
1045 } else { 1140 } else {
1046 /* default behaviour : take all the blocks into account */ 1141 /* default behaviour : take all the blocks into account */
1047 p->total = fsp->fsu_blocks; 1142 p->total = fsp->fsu_blocks;
1048 } 1143 }
1049 1144
1050 p->dused_units = p->used*fsp->fsu_blocksize/mult; 1145 p->dused_units = p->used*fsp->fsu_blocksize/mult;
1051 p->dfree_units = p->available*fsp->fsu_blocksize/mult; 1146 p->dfree_units = p->available*fsp->fsu_blocksize/mult;
1052 p->dtotal_units = p->total*fsp->fsu_blocksize/mult; 1147 p->dtotal_units = p->total*fsp->fsu_blocksize/mult;
1053 p->inodes_total = fsp->fsu_files; /* Total file nodes. */ 1148 /* Free file nodes. Not sure the workaround is required, but in case...*/
1054 p->inodes_free = fsp->fsu_ffree; /* Free file nodes. */ 1149 p->inodes_free = fsp->fsu_ffree;
1150 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */
1151 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree;
1152 if (freespace_ignore_reserved) {
1153 /* option activated : we subtract the root-reserved inodes from the total */
1154 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1155 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1156 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free;
1157 } else {
1158 /* default behaviour : take all the inodes into account */
1159 p->inodes_total = fsp->fsu_files;
1160 }
1055 np_add_name(&seen, p->best_match->me_mountdir); 1161 np_add_name(&seen, p->best_match->me_mountdir);
1056} 1162}
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index f206163..7ffce98 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -41,7 +41,7 @@ const char *email = "devel@monitoring-plugins.org";
41 41
42int process_arguments (int, char **); 42int process_arguments (int, char **);
43int validate_arguments (void); 43int validate_arguments (void);
44int error_scan (char *); 44int error_scan (char *, int *);
45int ip_match_cidr(const char *, const char *); 45int ip_match_cidr(const char *, const char *);
46unsigned long ip2long(const char *); 46unsigned long ip2long(const char *);
47void print_help (void); 47void print_help (void);
@@ -54,8 +54,10 @@ char ptr_server[ADDRESS_LENGTH] = "";
54int verbose = FALSE; 54int verbose = FALSE;
55char **expected_address = NULL; 55char **expected_address = NULL;
56int expected_address_cnt = 0; 56int expected_address_cnt = 0;
57int expect_nxdomain = FALSE;
57 58
58int expect_authority = FALSE; 59int expect_authority = FALSE;
60int all_match = FALSE;
59thresholds *time_thresholds = NULL; 61thresholds *time_thresholds = NULL;
60 62
61static int 63static int
@@ -73,7 +75,7 @@ main (int argc, char **argv)
73{ 75{
74 char *command_line = NULL; 76 char *command_line = NULL;
75 char input_buffer[MAX_INPUT_BUFFER]; 77 char input_buffer[MAX_INPUT_BUFFER];
76 char *address = NULL; /* comma seperated str with addrs/ptrs (sorted) */ 78 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
77 char **addresses = NULL; 79 char **addresses = NULL;
78 int n_addresses = 0; 80 int n_addresses = 0;
79 char *msg = NULL; 81 char *msg = NULL;
@@ -86,6 +88,7 @@ main (int argc, char **argv)
86 int parse_address = FALSE; /* This flag scans for Address: but only after Name: */ 88 int parse_address = FALSE; /* This flag scans for Address: but only after Name: */
87 output chld_out, chld_err; 89 output chld_out, chld_err;
88 size_t i; 90 size_t i;
91 int is_nxdomain = FALSE;
89 92
90 setlocale (LC_ALL, ""); 93 setlocale (LC_ALL, "");
91 bindtextdomain (PACKAGE, LOCALEDIR); 94 bindtextdomain (PACKAGE, LOCALEDIR);
@@ -168,8 +171,8 @@ main (int argc, char **argv)
168 temp_buffer++; 171 temp_buffer++;
169 172
170 /* Strip leading spaces */ 173 /* Strip leading spaces */
171 for (; *temp_buffer != '\0' && *temp_buffer == ' '; temp_buffer++) 174 while (*temp_buffer == ' ')
172 /* NOOP */; 175 temp_buffer++;
173 176
174 strip(temp_buffer); 177 strip(temp_buffer);
175 if (temp_buffer==NULL || strlen(temp_buffer)==0) { 178 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
@@ -185,7 +188,7 @@ main (int argc, char **argv)
185 } 188 }
186 189
187 190
188 result = error_scan (chld_out.line[i]); 191 result = error_scan (chld_out.line[i], &is_nxdomain);
189 if (result != STATE_OK) { 192 if (result != STATE_OK) {
190 msg = strchr (chld_out.line[i], ':'); 193 msg = strchr (chld_out.line[i], ':');
191 if(msg) msg++; 194 if(msg) msg++;
@@ -198,13 +201,20 @@ main (int argc, char **argv)
198 if (verbose) 201 if (verbose)
199 puts(chld_err.line[i]); 202 puts(chld_err.line[i]);
200 203
201 if (error_scan (chld_err.line[i]) != STATE_OK) { 204 if (error_scan (chld_err.line[i], &is_nxdomain) != STATE_OK) {
202 result = max_state (result, error_scan (chld_err.line[i])); 205 result = max_state (result, error_scan (chld_err.line[i], &is_nxdomain));
203 msg = strchr(input_buffer, ':'); 206 msg = strchr(input_buffer, ':');
204 if(msg) msg++; 207 if(msg)
208 msg++;
209 else
210 msg = input_buffer;
205 } 211 }
206 } 212 }
207 213
214 if (is_nxdomain && !expect_nxdomain) {
215 die (STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address);
216 }
217
208 if (addresses) { 218 if (addresses) {
209 int i,slen; 219 int i,slen;
210 char *adrp; 220 char *adrp;
@@ -228,16 +238,27 @@ main (int argc, char **argv)
228 if (result == STATE_OK && expected_address_cnt > 0) { 238 if (result == STATE_OK && expected_address_cnt > 0) {
229 result = STATE_CRITICAL; 239 result = STATE_CRITICAL;
230 temp_buffer = ""; 240 temp_buffer = "";
241 unsigned long expect_match = (1 << expected_address_cnt) - 1;
242 unsigned long addr_match = (1 << n_addresses) - 1;
231 243
232 for (i=0; i<expected_address_cnt; i++) { 244 for (i=0; i<expected_address_cnt; i++) {
245 int j;
233 /* check if we get a match on 'raw' ip or cidr */ 246 /* check if we get a match on 'raw' ip or cidr */
234 if ( strcmp(address, expected_address[i]) == 0 247 for (j=0; j<n_addresses; j++) {
235 || ip_match_cidr(address, expected_address[i]) ) 248 if ( strcmp(addresses[j], expected_address[i]) == 0
236 result = STATE_OK; 249 || ip_match_cidr(addresses[j], expected_address[i]) ) {
250 result = STATE_OK;
251 addr_match &= ~(1 << j);
252 expect_match &= ~(1 << i);
253 }
254 }
237 255
238 /* prepare an error string */ 256 /* prepare an error string */
239 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); 257 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
240 } 258 }
259 /* check if expected_address must cover all in addresses and none may be missing */
260 if (all_match && (expect_match != 0 || addr_match != 0))
261 result = STATE_CRITICAL;
241 if (result == STATE_CRITICAL) { 262 if (result == STATE_CRITICAL) {
242 /* Strip off last semicolon... */ 263 /* Strip off last semicolon... */
243 temp_buffer[strlen(temp_buffer)-2] = '\0'; 264 temp_buffer[strlen(temp_buffer)-2] = '\0';
@@ -245,6 +266,16 @@ main (int argc, char **argv)
245 } 266 }
246 } 267 }
247 268
269 if (expect_nxdomain) {
270 if (!is_nxdomain) {
271 result = STATE_CRITICAL;
272 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address);
273 } else {
274 if (address != NULL) free(address);
275 address = "NXDOMAIN";
276 }
277 }
278
248 /* check if authoritative */ 279 /* check if authoritative */
249 if (result == STATE_OK && expect_authority && non_authoritative) { 280 if (result == STATE_OK && expect_authority && non_authoritative) {
250 result = STATE_CRITICAL; 281 result = STATE_CRITICAL;
@@ -324,9 +355,15 @@ ip2long(const char* src) {
324} 355}
325 356
326int 357int
327error_scan (char *input_buffer) 358error_scan (char *input_buffer, int *is_nxdomain)
328{ 359{
329 360
361 const int nxdomain = strstr (input_buffer, "Non-existent") ||
362 strstr (input_buffer, "** server can't find") ||
363 strstr (input_buffer, "** Can't find") ||
364 strstr (input_buffer, "NXDOMAIN");
365 if (nxdomain) *is_nxdomain = TRUE;
366
330 /* the DNS lookup timed out */ 367 /* the DNS lookup timed out */
331 if (strstr (input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) || 368 if (strstr (input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
332 strstr (input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) || 369 strstr (input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
@@ -336,6 +373,8 @@ error_scan (char *input_buffer)
336 /* DNS server is not running... */ 373 /* DNS server is not running... */
337 else if (strstr (input_buffer, "No response from server")) 374 else if (strstr (input_buffer, "No response from server"))
338 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server); 375 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
376 else if (strstr (input_buffer, "no servers could be reached"))
377 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
339 378
340 /* Host name is valid, but server doesn't have records... */ 379 /* Host name is valid, but server doesn't have records... */
341 else if (strstr (input_buffer, "No records")) 380 else if (strstr (input_buffer, "No records"))
@@ -343,7 +382,7 @@ error_scan (char *input_buffer)
343 382
344 /* Connection was refused */ 383 /* Connection was refused */
345 else if (strstr (input_buffer, "Connection refused") || 384 else if (strstr (input_buffer, "Connection refused") ||
346 strstr (input_buffer, "Couldn't find server") || 385 strstr (input_buffer, "Couldn't find server") ||
347 strstr (input_buffer, "Refused") || 386 strstr (input_buffer, "Refused") ||
348 (strstr (input_buffer, "** server can't find") && 387 (strstr (input_buffer, "** server can't find") &&
349 strstr (input_buffer, ": REFUSED"))) 388 strstr (input_buffer, ": REFUSED")))
@@ -357,13 +396,6 @@ error_scan (char *input_buffer)
357 else if (strstr (input_buffer, "No information")) 396 else if (strstr (input_buffer, "No information"))
358 die (STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server); 397 die (STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
359 398
360 /* Host or domain name does not exist */
361 else if (strstr (input_buffer, "Non-existent") ||
362 strstr (input_buffer, "** server can't find") ||
363 strstr (input_buffer, "** Can't find") ||
364 strstr (input_buffer,"NXDOMAIN"))
365 die (STATE_CRITICAL, _("Domain %s was not found by the server\n"), query_address);
366
367 /* Network is unreachable */ 399 /* Network is unreachable */
368 else if (strstr (input_buffer, "Network is unreachable")) 400 else if (strstr (input_buffer, "Network is unreachable"))
369 die (STATE_CRITICAL, _("Network is unreachable\n")); 401 die (STATE_CRITICAL, _("Network is unreachable\n"));
@@ -400,7 +432,9 @@ process_arguments (int argc, char **argv)
400 {"server", required_argument, 0, 's'}, 432 {"server", required_argument, 0, 's'},
401 {"reverse-server", required_argument, 0, 'r'}, 433 {"reverse-server", required_argument, 0, 'r'},
402 {"expected-address", required_argument, 0, 'a'}, 434 {"expected-address", required_argument, 0, 'a'},
435 {"expect-nxdomain", no_argument, 0, 'n'},
403 {"expect-authority", no_argument, 0, 'A'}, 436 {"expect-authority", no_argument, 0, 'A'},
437 {"all", no_argument, 0, 'L'},
404 {"warning", required_argument, 0, 'w'}, 438 {"warning", required_argument, 0, 'w'},
405 {"critical", required_argument, 0, 'c'}, 439 {"critical", required_argument, 0, 'c'},
406 {0, 0, 0, 0} 440 {0, 0, 0, 0}
@@ -414,7 +448,7 @@ process_arguments (int argc, char **argv)
414 strcpy (argv[c], "-t"); 448 strcpy (argv[c], "-t");
415 449
416 while (1) { 450 while (1) {
417 c = getopt_long (argc, argv, "hVvAt:H:s:r:a:w:c:", long_opts, &opt_index); 451 c = getopt_long (argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
418 452
419 if (c == -1 || c == EOF) 453 if (c == -1 || c == EOF)
420 break; 454 break;
@@ -455,13 +489,33 @@ process_arguments (int argc, char **argv)
455 case 'a': /* expected address */ 489 case 'a': /* expected address */
456 if (strlen (optarg) >= ADDRESS_LENGTH) 490 if (strlen (optarg) >= ADDRESS_LENGTH)
457 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 491 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
458 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 492 if (strchr(optarg, ',') != NULL) {
459 expected_address[expected_address_cnt] = strdup(optarg); 493 char *comma = strchr(optarg, ',');
460 expected_address_cnt++; 494 while (comma != NULL) {
495 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
496 expected_address[expected_address_cnt] = strndup(optarg, comma - optarg);
497 expected_address_cnt++;
498 optarg = comma + 1;
499 comma = strchr(optarg, ',');
500 }
501 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
502 expected_address[expected_address_cnt] = strdup(optarg);
503 expected_address_cnt++;
504 } else {
505 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
506 expected_address[expected_address_cnt] = strdup(optarg);
507 expected_address_cnt++;
508 }
509 break;
510 case 'n': /* expect NXDOMAIN */
511 expect_nxdomain = TRUE;
461 break; 512 break;
462 case 'A': /* expect authority */ 513 case 'A': /* expect authority */
463 expect_authority = TRUE; 514 expect_authority = TRUE;
464 break; 515 break;
516 case 'L': /* all must match */
517 all_match = TRUE;
518 break;
465 case 'w': 519 case 'w':
466 warning = optarg; 520 warning = optarg;
467 break; 521 break;
@@ -497,8 +551,15 @@ process_arguments (int argc, char **argv)
497int 551int
498validate_arguments () 552validate_arguments ()
499{ 553{
500 if (query_address[0] == 0) 554 if (query_address[0] == 0) {
555 printf ("missing --host argument\n");
501 return ERROR; 556 return ERROR;
557 }
558
559 if (expected_address_cnt > 0 && expect_nxdomain) {
560 printf ("--expected-address and --expect-nxdomain cannot be combined\n");
561 return ERROR;
562 }
502 563
503 return OK; 564 return OK;
504} 565}
@@ -530,14 +591,19 @@ print_help (void)
530 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n"); 591 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
531 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end")); 592 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
532 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any")); 593 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
533 printf (" %s\n", _("value match). If multiple addresses are returned at once, you have to match")); 594 printf (" %s\n", _("value matches)."));
534 printf (" %s\n", _("the whole string of addresses separated with commas (sorted alphabetically).")); 595 printf (" -n, --expect-nxdomain\n");
596 printf (" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
597 printf (" %s\n", _("Cannot be used together with -a"));
535 printf (" -A, --expect-authority\n"); 598 printf (" -A, --expect-authority\n");
536 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup")); 599 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
537 printf (" -w, --warning=seconds\n"); 600 printf (" -w, --warning=seconds\n");
538 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off")); 601 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
539 printf (" -c, --critical=seconds\n"); 602 printf (" -c, --critical=seconds\n");
540 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off")); 603 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
604 printf (" -L, --all\n");
605 printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
606 printf (" %s\n", _("returned. Default off"));
541 607
542 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 608 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
543 609
@@ -549,5 +615,5 @@ void
549print_usage (void) 615print_usage (void)
550{ 616{
551 printf ("%s\n", _("Usage:")); 617 printf ("%s\n", _("Usage:"));
552 printf ("%s -H host [-s server] [-a expected-address] [-A] [-t timeout] [-w warn] [-c crit]\n", progname); 618 printf ("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
553} 619}
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index 521d0fe..23a9e99 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -37,6 +37,7 @@ const char *email = "devel@monitoring-plugins.org";
37#include "popen.h" 37#include "popen.h"
38#include "netutils.h" 38#include "netutils.h"
39#include "utils.h" 39#include "utils.h"
40#include <stdbool.h>
40 41
41enum { 42enum {
42 PACKET_COUNT = 1, 43 PACKET_COUNT = 1,
@@ -65,13 +66,14 @@ double crta;
65double wrta; 66double wrta;
66int cpl_p = FALSE; 67int cpl_p = FALSE;
67int wpl_p = FALSE; 68int wpl_p = FALSE;
69bool alive_p = FALSE;
68int crta_p = FALSE; 70int crta_p = FALSE;
69int wrta_p = FALSE; 71int wrta_p = FALSE;
70 72
71int 73int
72main (int argc, char **argv) 74main (int argc, char **argv)
73{ 75{
74/* normaly should be int result = STATE_UNKNOWN; */ 76/* normally should be int result = STATE_UNKNOWN; */
75 77
76 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
77 int result = 0; 79 int result = 0;
@@ -147,9 +149,11 @@ main (int argc, char **argv)
147 (void) fclose (child_stderr); 149 (void) fclose (child_stderr);
148 150
149 /* close the pipe */ 151 /* close the pipe */
150 if (result = spclose (child_process)) 152 result = spclose (child_process);
153 if (result) {
151 /* need to use max_state not max */ 154 /* need to use max_state not max */
152 status = max_state (status, STATE_WARNING); 155 status = max_state (status, STATE_WARNING);
156 }
153 157
154 if (result > 1 ) { 158 if (result > 1 ) {
155 status = max_state (status, STATE_UNKNOWN); 159 status = max_state (status, STATE_UNKNOWN);
@@ -171,10 +175,7 @@ main (int argc, char **argv)
171} 175}
172 176
173 177
174 178int textscan (char *buf) {
175int
176textscan (char *buf)
177{
178 char *rtastr = NULL; 179 char *rtastr = NULL;
179 char *losstr = NULL; 180 char *losstr = NULL;
180 char *xmtstr = NULL; 181 char *xmtstr = NULL;
@@ -183,6 +184,20 @@ textscan (char *buf)
183 double xmt; 184 double xmt;
184 int status = STATE_UNKNOWN; 185 int status = STATE_UNKNOWN;
185 186
187 /* stops testing after the first successful reply. */
188 if (alive_p && strstr(buf, "avg, 0% loss)")) {
189 rtastr = strstr (buf, "ms (");
190 rtastr = 1 + index(rtastr, '(');
191 rta = strtod(rtastr, NULL);
192 loss=strtod("0",NULL);
193 die (STATE_OK,
194 _("FPING %s - %s (rta=%f ms)|%s\n"),
195 state_text (STATE_OK), server_name,rta,
196 /* No loss since we only waited for the first reply
197 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100), */
198 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, TRUE, 0, FALSE, 0));
199 }
200
186 if (strstr (buf, "not found")) { 201 if (strstr (buf, "not found")) {
187 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name); 202 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
188 203
@@ -278,6 +293,7 @@ process_arguments (int argc, char **argv)
278 {"sourceif", required_argument, 0, 'I'}, 293 {"sourceif", required_argument, 0, 'I'},
279 {"critical", required_argument, 0, 'c'}, 294 {"critical", required_argument, 0, 'c'},
280 {"warning", required_argument, 0, 'w'}, 295 {"warning", required_argument, 0, 'w'},
296 {"alive", no_argument, 0, 'a'},
281 {"bytes", required_argument, 0, 'b'}, 297 {"bytes", required_argument, 0, 'b'},
282 {"number", required_argument, 0, 'n'}, 298 {"number", required_argument, 0, 'n'},
283 {"target-timeout", required_argument, 0, 'T'}, 299 {"target-timeout", required_argument, 0, 'T'},
@@ -304,7 +320,7 @@ process_arguments (int argc, char **argv)
304 } 320 }
305 321
306 while (1) { 322 while (1) {
307 c = getopt_long (argc, argv, "+hVvH:S:c:w:b:n:T:i:I:46", longopts, &option); 323 c = getopt_long (argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:46", longopts, &option);
308 324
309 if (c == -1 || c == EOF || c == 1) 325 if (c == -1 || c == EOF || c == 1)
310 break; 326 break;
@@ -312,6 +328,9 @@ process_arguments (int argc, char **argv)
312 switch (c) { 328 switch (c) {
313 case '?': /* print short usage statement if args not parsable */ 329 case '?': /* print short usage statement if args not parsable */
314 usage5 (); 330 usage5 ();
331 case 'a': /* host alive mode */
332 alive_p = TRUE;
333 break;
315 case 'h': /* help */ 334 case 'h': /* help */
316 print_help (); 335 print_help ();
317 exit (STATE_UNKNOWN); 336 exit (STATE_UNKNOWN);
@@ -335,6 +354,7 @@ process_arguments (int argc, char **argv)
335 break; 354 break;
336 case 'I': /* sourceip */ 355 case 'I': /* sourceip */
337 sourceif = strscpy (sourceif, optarg); 356 sourceif = strscpy (sourceif, optarg);
357 break;
338 case '4': /* IPv4 only */ 358 case '4': /* IPv4 only */
339 address_family = AF_INET; 359 address_family = AF_INET;
340 break; 360 break;
@@ -446,9 +466,7 @@ get_threshold (char *arg, char *rv[2])
446} 466}
447 467
448 468
449void 469void print_help (void) {
450print_help (void)
451{
452 470
453 print_revision (progname, NP_VERSION); 471 print_revision (progname, NP_VERSION);
454 472
@@ -474,6 +492,8 @@ print_help (void)
474 printf (" %s\n", _("warning threshold pair")); 492 printf (" %s\n", _("warning threshold pair"));
475 printf (" %s\n", "-c, --critical=THRESHOLD"); 493 printf (" %s\n", "-c, --critical=THRESHOLD");
476 printf (" %s\n", _("critical threshold pair")); 494 printf (" %s\n", _("critical threshold pair"));
495 printf (" %s\n", "-a, --alive");
496 printf (" %s\n", _("Return OK after first successful reply"));
477 printf (" %s\n", "-b, --bytes=INTEGER"); 497 printf (" %s\n", "-b, --bytes=INTEGER");
478 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE); 498 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE);
479 printf (" %s\n", "-n, --number=INTEGER"); 499 printf (" %s\n", "-n, --number=INTEGER");
diff --git a/plugins/check_game.c b/plugins/check_game.c
index 709dae1..a534b69 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -318,7 +318,7 @@ print_help (void)
318 printf ("%s\n", _("Notes:")); 318 printf ("%s\n", _("Notes:"));
319 printf (" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool.")); 319 printf (" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
320 printf (" %s\n", _("If you don't have the package installed, you will need to download it from")); 320 printf (" %s\n", _("If you don't have the package installed, you will need to download it from"));
321 printf (" %s\n", _("http://www.activesw.com/people/steve/qstat.html before you can use this plugin.")); 321 printf (" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
322 322
323 printf (UT_SUPPORT); 323 printf (UT_SUPPORT);
324} 324}
diff --git a/plugins/check_hpjd.c b/plugins/check_hpjd.c
index f159f5a..c34bb08 100644
--- a/plugins/check_hpjd.c
+++ b/plugins/check_hpjd.c
@@ -66,7 +66,8 @@ void print_usage (void);
66 66
67char *community = NULL; 67char *community = NULL;
68char *address = NULL; 68char *address = NULL;
69char *port = NULL; 69unsigned int port = 0;
70int check_paper_out = 1;
70 71
71int 72int
72main (int argc, char **argv) 73main (int argc, char **argv)
@@ -120,8 +121,12 @@ main (int argc, char **argv)
120 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY); 121 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
121 122
122 /* get the command to run */ 123 /* get the command to run */
123 sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%hd %s", PATH_TO_SNMPGET, community, 124 sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s",
124 address, port, query_string); 125 PATH_TO_SNMPGET,
126 community,
127 address,
128 port,
129 query_string);
125 130
126 /* run the command */ 131 /* run the command */
127 child_process = spopen (command_line); 132 child_process = spopen (command_line);
@@ -240,7 +245,8 @@ main (int argc, char **argv)
240 strcpy (errmsg, _("Paper Jam")); 245 strcpy (errmsg, _("Paper Jam"));
241 } 246 }
242 else if (paper_out) { 247 else if (paper_out) {
243 result = STATE_WARNING; 248 if (check_paper_out)
249 result = STATE_WARNING;
244 strcpy (errmsg, _("Out of Paper")); 250 strcpy (errmsg, _("Out of Paper"));
245 } 251 }
246 else if (line_status == OFFLINE) { 252 else if (line_status == OFFLINE) {
@@ -325,7 +331,7 @@ process_arguments (int argc, char **argv)
325 331
326 332
327 while (1) { 333 while (1) {
328 c = getopt_long (argc, argv, "+hVH:C:p:", longopts, &option); 334 c = getopt_long (argc, argv, "+hVH:C:p:D", longopts, &option);
329 335
330 if (c == -1 || c == EOF || c == 1) 336 if (c == -1 || c == EOF || c == 1)
331 break; 337 break;
@@ -348,6 +354,9 @@ process_arguments (int argc, char **argv)
348 else 354 else
349 port = atoi(optarg); 355 port = atoi(optarg);
350 break; 356 break;
357 case 'D': /* disable paper out check*/
358 check_paper_out = 0;
359 break;
351 case 'V': /* version */ 360 case 'V': /* version */
352 print_revision (progname, NP_VERSION); 361 print_revision (progname, NP_VERSION);
353 exit (STATE_UNKNOWN); 362 exit (STATE_UNKNOWN);
@@ -376,11 +385,8 @@ process_arguments (int argc, char **argv)
376 community = strdup (DEFAULT_COMMUNITY); 385 community = strdup (DEFAULT_COMMUNITY);
377 } 386 }
378 387
379 if (port == NULL) { 388 if (port == 0) {
380 if (argv[c] != NULL ) 389 port = atoi(DEFAULT_PORT);
381 port = argv[c];
382 else
383 port = atoi (DEFAULT_PORT);
384 } 390 }
385 391
386 return validate_arguments (); 392 return validate_arguments ();
@@ -420,6 +426,8 @@ print_help (void)
420 printf (" %s", _("Specify the port to check ")); 426 printf (" %s", _("Specify the port to check "));
421 printf (_("(default=%s)"), DEFAULT_PORT); 427 printf (_("(default=%s)"), DEFAULT_PORT);
422 printf ("\n"); 428 printf ("\n");
429 printf (" %s\n", "-D");
430 printf (" %s", _("Disable paper check "));
423 431
424 printf (UT_SUPPORT); 432 printf (UT_SUPPORT);
425} 433}
@@ -430,5 +438,5 @@ void
430print_usage (void) 438print_usage (void)
431{ 439{
432 printf ("%s\n", _("Usage:")); 440 printf ("%s\n", _("Usage:"));
433 printf ("%s -H host [-C community] [-p port]\n", progname); 441 printf ("%s -H host [-C community] [-p port] [-D]\n", progname);
434} 442}
diff --git a/plugins/check_http.c b/plugins/check_http.c
index 86a36c2..718c8ee 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -31,13 +31,14 @@
31* 31*
32*****************************************************************************/ 32*****************************************************************************/
33 33
34/* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
35
36const char *progname = "check_http"; 34const char *progname = "check_http";
37const char *copyright = "1999-2013"; 35const char *copyright = "1999-2022";
38const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
39 37
38// Do NOT sort those headers, it will break the build
39// TODO: Fix this
40#include "common.h" 40#include "common.h"
41#include "base64.h"
41#include "netutils.h" 42#include "netutils.h"
42#include "utils.h" 43#include "utils.h"
43#include "base64.h" 44#include "base64.h"
@@ -52,11 +53,13 @@ enum {
52 MAX_IPV4_HOSTLENGTH = 255, 53 MAX_IPV4_HOSTLENGTH = 255,
53 HTTP_PORT = 80, 54 HTTP_PORT = 80,
54 HTTPS_PORT = 443, 55 HTTPS_PORT = 443,
55 MAX_PORT = 65535 56 MAX_PORT = 65535,
57 DEFAULT_MAX_REDIRS = 15
56}; 58};
57 59
58#ifdef HAVE_SSL 60#ifdef HAVE_SSL
59int check_cert = FALSE; 61bool check_cert = false;
62bool continue_after_check_cert = false;
60int ssl_version = 0; 63int ssl_version = 0;
61int days_till_exp_warn, days_till_exp_crit; 64int days_till_exp_warn, days_till_exp_crit;
62char *randbuff; 65char *randbuff;
@@ -67,12 +70,12 @@ X509 *server_cert;
67# define my_recv(buf, len) read(sd, buf, len) 70# define my_recv(buf, len) read(sd, buf, len)
68# define my_send(buf, len) send(sd, buf, len, 0) 71# define my_send(buf, len) send(sd, buf, len, 0)
69#endif /* HAVE_SSL */ 72#endif /* HAVE_SSL */
70int no_body = FALSE; 73bool no_body = false;
71int maximum_age = -1; 74int maximum_age = -1;
72 75
73enum { 76enum {
74 REGS = 2, 77 REGS = 2,
75 MAX_RE_SIZE = 256 78 MAX_RE_SIZE = 1024
76}; 79};
77#include "regex.h" 80#include "regex.h"
78regex_t preg; 81regex_t preg;
@@ -89,7 +92,7 @@ struct timeval tv_temp;
89#define HTTP_URL "/" 92#define HTTP_URL "/"
90#define CRLF "\r\n" 93#define CRLF "\r\n"
91 94
92int specify_port = FALSE; 95bool specify_port = false;
93int server_port = HTTP_PORT; 96int server_port = HTTP_PORT;
94int virtual_port = 0; 97int virtual_port = 0;
95char server_port_text[6] = ""; 98char server_port_text[6] = "";
@@ -104,38 +107,39 @@ int server_expect_yn = 0;
104char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 107char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
105char header_expect[MAX_INPUT_BUFFER] = ""; 108char header_expect[MAX_INPUT_BUFFER] = "";
106char string_expect[MAX_INPUT_BUFFER] = ""; 109char string_expect[MAX_INPUT_BUFFER] = "";
107char output_header_search[30] = "";
108char output_string_search[30] = "";
109char *warning_thresholds = NULL; 110char *warning_thresholds = NULL;
110char *critical_thresholds = NULL; 111char *critical_thresholds = NULL;
111thresholds *thlds; 112thresholds *thlds;
112char user_auth[MAX_INPUT_BUFFER] = ""; 113char user_auth[MAX_INPUT_BUFFER] = "";
113char proxy_auth[MAX_INPUT_BUFFER] = ""; 114char proxy_auth[MAX_INPUT_BUFFER] = "";
114int display_html = FALSE; 115bool display_html = false;
115char **http_opt_headers; 116char **http_opt_headers;
116int http_opt_headers_count = 0; 117int http_opt_headers_count = 0;
117int onredirect = STATE_OK; 118int onredirect = STATE_OK;
118int followsticky = STICKY_NONE; 119int followsticky = STICKY_NONE;
119int use_ssl = FALSE; 120bool use_ssl = false;
120int use_sni = FALSE; 121bool use_sni = false;
121int verbose = FALSE; 122bool verbose = false;
122int show_extended_perfdata = FALSE; 123bool show_extended_perfdata = false;
124bool show_body = false;
123int sd; 125int sd;
124int min_page_len = 0; 126int min_page_len = 0;
125int max_page_len = 0; 127int max_page_len = 0;
126int redir_depth = 0; 128int redir_depth = 0;
127int max_depth = 15; 129int max_depth = DEFAULT_MAX_REDIRS;
128char *http_method; 130char *http_method;
131char *http_method_proxy;
129char *http_post_data; 132char *http_post_data;
130char *http_content_type; 133char *http_content_type;
131char buffer[MAX_INPUT_BUFFER]; 134char buffer[MAX_INPUT_BUFFER];
132char *client_cert = NULL; 135char *client_cert = NULL;
133char *client_privkey = NULL; 136char *client_privkey = NULL;
134 137
135int process_arguments (int, char **); 138// Forward function declarations
139bool process_arguments (int, char **);
136int check_http (void); 140int check_http (void);
137void redir (char *pos, char *status_line); 141void redir (char *pos, char *status_line);
138int server_type_check(const char *type); 142bool server_type_check(const char *type);
139int server_port_check(int ssl_flag); 143int server_port_check(int ssl_flag);
140char *perfd_time (double microsec); 144char *perfd_time (double microsec);
141char *perfd_time_connect (double microsec); 145char *perfd_time_connect (double microsec);
@@ -146,6 +150,7 @@ char *perfd_time_transfer (double microsec);
146char *perfd_size (int page_len); 150char *perfd_size (int page_len);
147void print_help (void); 151void print_help (void);
148void print_usage (void); 152void print_usage (void);
153char *unchunk_content(const char *content);
149 154
150int 155int
151main (int argc, char **argv) 156main (int argc, char **argv)
@@ -165,10 +170,10 @@ main (int argc, char **argv)
165 /* Parse extra opts if any */ 170 /* Parse extra opts if any */
166 argv=np_extra_opts (&argc, argv, progname); 171 argv=np_extra_opts (&argc, argv, progname);
167 172
168 if (process_arguments (argc, argv) == ERROR) 173 if (process_arguments (argc, argv) == false)
169 usage4 (_("Could not parse arguments")); 174 usage4 (_("Could not parse arguments"));
170 175
171 if (display_html == TRUE) 176 if (display_html == true)
172 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 177 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
173 use_ssl ? "https" : "http", host_name ? host_name : server_address, 178 use_ssl ? "https" : "http", host_name ? host_name : server_address,
174 server_port, server_url); 179 server_port, server_url);
@@ -191,9 +196,11 @@ test_file (char *path)
191 usage2 (_("file does not exist or is not readable"), path); 196 usage2 (_("file does not exist or is not readable"), path);
192} 197}
193 198
194/* process command-line arguments */ 199/*
195int 200 * process command-line arguments
196process_arguments (int argc, char **argv) 201 * returns true on success, false otherwise
202 */
203bool process_arguments (int argc, char **argv)
197{ 204{
198 int c = 1; 205 int c = 1;
199 char *p; 206 char *p;
@@ -201,7 +208,9 @@ process_arguments (int argc, char **argv)
201 208
202 enum { 209 enum {
203 INVERT_REGEX = CHAR_MAX + 1, 210 INVERT_REGEX = CHAR_MAX + 1,
204 SNI_OPTION 211 SNI_OPTION,
212 MAX_REDIRS_OPTION,
213 CONTINUE_AFTER_CHECK_CERT
205 }; 214 };
206 215
207 int option = 0; 216 int option = 0;
@@ -229,6 +238,7 @@ process_arguments (int argc, char **argv)
229 {"certificate", required_argument, 0, 'C'}, 238 {"certificate", required_argument, 0, 'C'},
230 {"client-cert", required_argument, 0, 'J'}, 239 {"client-cert", required_argument, 0, 'J'},
231 {"private-key", required_argument, 0, 'K'}, 240 {"private-key", required_argument, 0, 'K'},
241 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
232 {"useragent", required_argument, 0, 'A'}, 242 {"useragent", required_argument, 0, 'A'},
233 {"header", required_argument, 0, 'k'}, 243 {"header", required_argument, 0, 'k'},
234 {"no-body", no_argument, 0, 'N'}, 244 {"no-body", no_argument, 0, 'N'},
@@ -239,11 +249,13 @@ process_arguments (int argc, char **argv)
239 {"use-ipv4", no_argument, 0, '4'}, 249 {"use-ipv4", no_argument, 0, '4'},
240 {"use-ipv6", no_argument, 0, '6'}, 250 {"use-ipv6", no_argument, 0, '6'},
241 {"extended-perfdata", no_argument, 0, 'E'}, 251 {"extended-perfdata", no_argument, 0, 'E'},
252 {"show-body", no_argument, 0, 'B'},
253 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
242 {0, 0, 0, 0} 254 {0, 0, 0, 0}
243 }; 255 };
244 256
245 if (argc < 2) 257 if (argc < 2)
246 return ERROR; 258 return false;
247 259
248 for (c = 1; c < argc; c++) { 260 for (c = 1; c < argc; c++) {
249 if (strcmp ("-to", argv[c]) == 0) 261 if (strcmp ("-to", argv[c]) == 0)
@@ -259,7 +271,7 @@ process_arguments (int argc, char **argv)
259 } 271 }
260 272
261 while (1) { 273 while (1) {
262 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NE", longopts, &option); 274 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB", longopts, &option);
263 if (c == -1 || c == EOF) 275 if (c == -1 || c == EOF)
264 break; 276 break;
265 277
@@ -299,10 +311,10 @@ process_arguments (int argc, char **argv)
299 /* xasprintf (&http_opt_headers, "%s", optarg); */ 311 /* xasprintf (&http_opt_headers, "%s", optarg); */
300 break; 312 break;
301 case 'L': /* show html link */ 313 case 'L': /* show html link */
302 display_html = TRUE; 314 display_html = true;
303 break; 315 break;
304 case 'n': /* do not show html link */ 316 case 'n': /* do not show html link */
305 display_html = FALSE; 317 display_html = false;
306 break; 318 break;
307 case 'C': /* Check SSL cert validity */ 319 case 'C': /* Check SSL cert validity */
308#ifdef HAVE_SSL 320#ifdef HAVE_SSL
@@ -323,9 +335,14 @@ process_arguments (int argc, char **argv)
323 usage2 (_("Invalid certificate expiration period"), optarg); 335 usage2 (_("Invalid certificate expiration period"), optarg);
324 days_till_exp_warn = atoi (optarg); 336 days_till_exp_warn = atoi (optarg);
325 } 337 }
326 check_cert = TRUE; 338 check_cert = true;
327 goto enable_ssl; 339 goto enable_ssl;
328#endif 340#endif
341 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
342#ifdef HAVE_SSL
343 continue_after_check_cert = true;
344 break;
345#endif
329 case 'J': /* use client certificate */ 346 case 'J': /* use client certificate */
330#ifdef HAVE_SSL 347#ifdef HAVE_SSL
331 test_file(optarg); 348 test_file(optarg);
@@ -343,7 +360,7 @@ process_arguments (int argc, char **argv)
343 enable_ssl: 360 enable_ssl:
344 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple 361 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple
345 parameters, like -S and -C combinations */ 362 parameters, like -S and -C combinations */
346 use_ssl = TRUE; 363 use_ssl = true;
347 if (c=='S' && optarg != NULL) { 364 if (c=='S' && optarg != NULL) {
348 int got_plus = strchr(optarg, '+') != NULL; 365 int got_plus = strchr(optarg, '+') != NULL;
349 366
@@ -360,7 +377,7 @@ process_arguments (int argc, char **argv)
360 else 377 else
361 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); 378 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)"));
362 } 379 }
363 if (specify_port == FALSE) 380 if (specify_port == false)
364 server_port = HTTPS_PORT; 381 server_port = HTTPS_PORT;
365#else 382#else
366 /* -C -J and -K fall through to here without SSL */ 383 /* -C -J and -K fall through to here without SSL */
@@ -368,8 +385,15 @@ process_arguments (int argc, char **argv)
368#endif 385#endif
369 break; 386 break;
370 case SNI_OPTION: 387 case SNI_OPTION:
371 use_sni = TRUE; 388 use_sni = true;
372 break; 389 break;
390 case MAX_REDIRS_OPTION:
391 if (!is_intnonneg (optarg))
392 usage2 (_("Invalid max_redirs count"), optarg);
393 else {
394 max_depth = atoi (optarg);
395 }
396 break;
373 case 'f': /* onredirect */ 397 case 'f': /* onredirect */
374 if (!strcmp (optarg, "stickyport")) 398 if (!strcmp (optarg, "stickyport"))
375 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; 399 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
@@ -399,7 +423,7 @@ process_arguments (int argc, char **argv)
399 host_name_length = strlen (host_name) - strlen (p) - 1; 423 host_name_length = strlen (host_name) - strlen (p) - 1;
400 free (host_name); 424 free (host_name);
401 host_name = strndup (optarg, host_name_length); 425 host_name = strndup (optarg, host_name_length);
402 if (specify_port == FALSE) 426 if (specify_port == false)
403 server_port = virtual_port; 427 server_port = virtual_port;
404 } 428 }
405 } else if ((p = strchr (host_name, ':')) != NULL 429 } else if ((p = strchr (host_name, ':')) != NULL
@@ -409,7 +433,7 @@ process_arguments (int argc, char **argv)
409 host_name_length = strlen (host_name) - strlen (p) - 1; 433 host_name_length = strlen (host_name) - strlen (p) - 1;
410 free (host_name); 434 free (host_name);
411 host_name = strndup (optarg, host_name_length); 435 host_name = strndup (optarg, host_name_length);
412 if (specify_port == FALSE) 436 if (specify_port == false)
413 server_port = virtual_port; 437 server_port = virtual_port;
414 } 438 }
415 break; 439 break;
@@ -425,7 +449,7 @@ process_arguments (int argc, char **argv)
425 usage2 (_("Invalid port number"), optarg); 449 usage2 (_("Invalid port number"), optarg);
426 else { 450 else {
427 server_port = atoi (optarg); 451 server_port = atoi (optarg);
428 specify_port = TRUE; 452 specify_port = true;
429 } 453 }
430 break; 454 break;
431 case 'a': /* authorization info */ 455 case 'a': /* authorization info */
@@ -446,6 +470,12 @@ process_arguments (int argc, char **argv)
446 if (http_method) 470 if (http_method)
447 free(http_method); 471 free(http_method);
448 http_method = strdup (optarg); 472 http_method = strdup (optarg);
473 char *tmp;
474 if ((tmp = strstr(http_method, ":")) > 0) {
475 tmp[0] = '\0';
476 http_method = http_method;
477 http_method_proxy = ++tmp;
478 }
449 break; 479 break;
450 case 'd': /* string or substring */ 480 case 'd': /* string or substring */
451 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 481 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1);
@@ -468,6 +498,7 @@ process_arguments (int argc, char **argv)
468 break; 498 break;
469 case 'R': /* regex */ 499 case 'R': /* regex */
470 cflags |= REG_ICASE; 500 cflags |= REG_ICASE;
501 // fall through
471 case 'r': /* regex */ 502 case 'r': /* regex */
472 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 503 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
473 regexp[MAX_RE_SIZE - 1] = 0; 504 regexp[MAX_RE_SIZE - 1] = 0;
@@ -475,7 +506,7 @@ process_arguments (int argc, char **argv)
475 if (errcode != 0) { 506 if (errcode != 0) {
476 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 507 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
477 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 508 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
478 return ERROR; 509 return false;
479 } 510 }
480 break; 511 break;
481 case INVERT_REGEX: 512 case INVERT_REGEX:
@@ -492,7 +523,7 @@ process_arguments (int argc, char **argv)
492#endif 523#endif
493 break; 524 break;
494 case 'v': /* verbose */ 525 case 'v': /* verbose */
495 verbose = TRUE; 526 verbose = true;
496 break; 527 break;
497 case 'm': /* min_page_length */ 528 case 'm': /* min_page_length */
498 { 529 {
@@ -517,7 +548,7 @@ process_arguments (int argc, char **argv)
517 break; 548 break;
518 } 549 }
519 case 'N': /* no-body */ 550 case 'N': /* no-body */
520 no_body = TRUE; 551 no_body = true;
521 break; 552 break;
522 case 'M': /* max-age */ 553 case 'M': /* max-age */
523 { 554 {
@@ -538,7 +569,10 @@ process_arguments (int argc, char **argv)
538 } 569 }
539 break; 570 break;
540 case 'E': /* show extended perfdata */ 571 case 'E': /* show extended perfdata */
541 show_extended_perfdata = TRUE; 572 show_extended_perfdata = true;
573 break;
574 case 'B': /* print body content after status line */
575 show_body = true;
542 break; 576 break;
543 } 577 }
544 } 578 }
@@ -566,13 +600,16 @@ process_arguments (int argc, char **argv)
566 if (http_method == NULL) 600 if (http_method == NULL)
567 http_method = strdup ("GET"); 601 http_method = strdup ("GET");
568 602
603 if (http_method_proxy == NULL)
604 http_method_proxy = strdup ("GET");
605
569 if (client_cert && !client_privkey) 606 if (client_cert && !client_privkey)
570 usage4 (_("If you use a client certificate you must also specify a private key file")); 607 usage4 (_("If you use a client certificate you must also specify a private key file"));
571 608
572 if (virtual_port == 0) 609 if (virtual_port == 0)
573 virtual_port = server_port; 610 virtual_port = server_port;
574 611
575 return TRUE; 612 return true;
576} 613}
577 614
578 615
@@ -912,10 +949,25 @@ check_http (void)
912 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */ 949 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
913 950
914 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 951 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
915 && host_name != NULL && use_ssl == TRUE) { 952 && host_name != NULL && use_ssl == true) {
916 953
917 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT); 954 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT);
918 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent); 955 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent);
956 if (strlen(proxy_auth)) {
957 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth);
958 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
959 }
960 /* optionally send any other header tag */
961 if (http_opt_headers_count) {
962 for (i = 0; i < http_opt_headers_count ; i++) {
963 if (force_host_header != http_opt_headers[i]) {
964 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]);
965 }
966 }
967 /* This cannot be free'd here because a redirection will then try to access this and segfault */
968 /* Covered in a testcase in tests/check_http.t */
969 /* free(http_opt_headers); */
970 }
919 asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf); 971 asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf);
920 asprintf (&buf, "%sHost: %s\r\n", buf, host_name); 972 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
921 /* we finished our request, send empty line with CRLF */ 973 /* we finished our request, send empty line with CRLF */
@@ -931,7 +983,7 @@ check_http (void)
931 } 983 }
932#ifdef HAVE_SSL 984#ifdef HAVE_SSL
933 elapsed_time_connect = (double)microsec_connect / 1.0e6; 985 elapsed_time_connect = (double)microsec_connect / 1.0e6;
934 if (use_ssl == TRUE) { 986 if (use_ssl == true) {
935 gettimeofday (&tv_temp, NULL); 987 gettimeofday (&tv_temp, NULL);
936 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); 988 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
937 if (verbose) printf ("SSL initialized\n"); 989 if (verbose) printf ("SSL initialized\n");
@@ -939,18 +991,20 @@ check_http (void)
939 die (STATE_CRITICAL, NULL); 991 die (STATE_CRITICAL, NULL);
940 microsec_ssl = deltime (tv_temp); 992 microsec_ssl = deltime (tv_temp);
941 elapsed_time_ssl = (double)microsec_ssl / 1.0e6; 993 elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
942 if (check_cert == TRUE) { 994 if (check_cert == true) {
943 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 995 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
944 if (sd) close(sd); 996 if (continue_after_check_cert == false) {
945 np_net_ssl_cleanup(); 997 if (sd) close(sd);
946 return result; 998 np_net_ssl_cleanup();
999 return result;
1000 }
947 } 1001 }
948 } 1002 }
949#endif /* HAVE_SSL */ 1003#endif /* HAVE_SSL */
950 1004
951 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 1005 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
952 && host_name != NULL && use_ssl == TRUE) 1006 && host_name != NULL && use_ssl == true)
953 asprintf (&buf, "%s %s %s\r\n%s\r\n", "GET", server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1007 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
954 else 1008 else
955 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1009 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
956 1010
@@ -977,10 +1031,10 @@ check_http (void)
977 * 14.23). Some server applications/configurations cause trouble if the 1031 * 14.23). Some server applications/configurations cause trouble if the
978 * (default) port is explicitly specified in the "Host:" header line. 1032 * (default) port is explicitly specified in the "Host:" header line.
979 */ 1033 */
980 if ((use_ssl == FALSE && virtual_port == HTTP_PORT) || 1034 if ((use_ssl == false && virtual_port == HTTP_PORT) ||
981 (use_ssl == TRUE && virtual_port == HTTPS_PORT) || 1035 (use_ssl == true && virtual_port == HTTPS_PORT) ||
982 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 1036 (server_address != NULL && strcmp(http_method, "CONNECT") == 0
983 && host_name != NULL && use_ssl == TRUE)) 1037 && host_name != NULL && use_ssl == true))
984 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1038 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name);
985 else 1039 else
986 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port); 1040 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
@@ -1020,9 +1074,8 @@ check_http (void)
1020 } 1074 }
1021 1075
1022 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data)); 1076 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
1023 xasprintf (&buf, "%s%s%s", buf, http_post_data, CRLF); 1077 xasprintf (&buf, "%s%s", buf, http_post_data);
1024 } 1078 } else {
1025 else {
1026 /* or just a newline so the server knows we're done with the request */ 1079 /* or just a newline so the server knows we're done with the request */
1027 xasprintf (&buf, "%s%s", buf, CRLF); 1080 xasprintf (&buf, "%s%s", buf, CRLF);
1028 } 1081 }
@@ -1046,9 +1099,14 @@ check_http (void)
1046 *pos = ' '; 1099 *pos = ' ';
1047 } 1100 }
1048 buffer[i] = '\0'; 1101 buffer[i] = '\0';
1049 xasprintf (&full_page_new, "%s%s", full_page, buffer); 1102
1050 free (full_page); 1103 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL)
1104 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
1105
1106 memmove(&full_page_new[pagesize], buffer, i + 1);
1107
1051 full_page = full_page_new; 1108 full_page = full_page_new;
1109
1052 pagesize += i; 1110 pagesize += i;
1053 1111
1054 if (no_body && document_headers_done (full_page)) { 1112 if (no_body && document_headers_done (full_page)) {
@@ -1060,25 +1118,7 @@ check_http (void)
1060 elapsed_time_transfer = (double)microsec_transfer / 1.0e6; 1118 elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
1061 1119
1062 if (i < 0 && errno != ECONNRESET) { 1120 if (i < 0 && errno != ECONNRESET) {
1063#ifdef HAVE_SSL 1121 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1064 /*
1065 if (use_ssl) {
1066 sslerr=SSL_get_error(ssl, i);
1067 if ( sslerr == SSL_ERROR_SSL ) {
1068 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
1069 } else {
1070 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1071 }
1072 }
1073 else {
1074 */
1075#endif
1076 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1077#ifdef HAVE_SSL
1078 /* XXX
1079 }
1080 */
1081#endif
1082 } 1122 }
1083 1123
1084 /* return a CRITICAL status if we couldn't read any data */ 1124 /* return a CRITICAL status if we couldn't read any data */
@@ -1140,6 +1180,8 @@ check_http (void)
1140 xasprintf (&msg, 1180 xasprintf (&msg,
1141 _("Invalid HTTP response received from host on port %d: %s\n"), 1181 _("Invalid HTTP response received from host on port %d: %s\n"),
1142 server_port, status_line); 1182 server_port, status_line);
1183 if (show_body)
1184 xasprintf (&msg, _("%s\n%s"), msg, page);
1143 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg); 1185 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
1144 } 1186 }
1145 1187
@@ -1201,32 +1243,73 @@ check_http (void)
1201 } 1243 }
1202 1244
1203 /* Page and Header content checks go here */ 1245 /* Page and Header content checks go here */
1204 if (strlen (header_expect)) { 1246 if (strlen(header_expect) > 0) {
1205 if (!strstr (header, header_expect)) { 1247 if (strstr(header, header_expect) == NULL) {
1206 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search)); 1248 // We did not find the header, the rest is for building the output and setting the state
1207 if(output_header_search[sizeof(output_header_search)-1]!='\0') { 1249 char output_header_search[30] = "";
1208 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4); 1250
1251 strncpy(&output_header_search[0], header_expect,
1252 sizeof(output_header_search));
1253
1254 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1255 bcopy("...",
1256 &output_header_search[sizeof(output_header_search) - 4],
1257 4);
1209 } 1258 }
1210 xasprintf (&msg, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1259
1260 xasprintf (&msg,
1261 _("%sheader '%s' not found on '%s://%s:%d%s', "),
1262 msg,
1263 output_header_search, use_ssl ? "https" : "http",
1264 host_name ? host_name : server_address, server_port,
1265 server_url);
1266
1211 result = STATE_CRITICAL; 1267 result = STATE_CRITICAL;
1212 } 1268 }
1213 } 1269 }
1214 1270
1271 // At this point we should test if the content is chunked and unchunk it, so
1272 // it can be searched (and possibly printed)
1273 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
1274 regex_t chunked_header_regex;
1275
1276 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
1277 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex");
1278 }
1279
1280 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found
1215 1281
1216 if (strlen (string_expect)) { 1282 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
1217 if (!strstr (page, string_expect)) { 1283 if (verbose) {
1218 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 1284 printf("Found chunked content\n");
1219 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1285 }
1220 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1286 // We actually found the chunked header
1287 char *tmp = unchunk_content(page);
1288 if (tmp == NULL) {
1289 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body");
1290 }
1291 page = tmp;
1292 }
1293
1294 if (strlen(string_expect) > 0) {
1295 if (!strstr(page, string_expect)) {
1296 // We found the string the body, the rest is for building the output
1297 char output_string_search[30] = "";
1298 strncpy(&output_string_search[0], string_expect,
1299 sizeof(output_string_search));
1300 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1301 bcopy("...", &output_string_search[sizeof(output_string_search) - 4],
1302 4);
1221 } 1303 }
1222 xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1304 xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1223 result = STATE_CRITICAL; 1305 result = STATE_CRITICAL;
1224 } 1306 }
1225 } 1307 }
1226 1308
1227 if (strlen (regexp)) { 1309 if (strlen(regexp) > 0) {
1228 errcode = regexec (&preg, page, REGS, pmatch, 0); 1310 errcode = regexec(&preg, page, REGS, pmatch, 0);
1229 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) { 1311 if ((errcode == 0 && invert_regex == 0) ||
1312 (errcode == REG_NOMATCH && invert_regex == 1)) {
1230 /* OK - No-op to avoid changing the logic around it */ 1313 /* OK - No-op to avoid changing the logic around it */
1231 result = max_state_alt(STATE_OK, result); 1314 result = max_state_alt(STATE_OK, result);
1232 } 1315 }
@@ -1278,7 +1361,7 @@ check_http (void)
1278 perfd_time (elapsed_time), 1361 perfd_time (elapsed_time),
1279 perfd_size (page_len), 1362 perfd_size (page_len),
1280 perfd_time_connect (elapsed_time_connect), 1363 perfd_time_connect (elapsed_time_connect),
1281 use_ssl == TRUE ? perfd_time_ssl (elapsed_time_ssl) : "", 1364 use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "",
1282 perfd_time_headers (elapsed_time_headers), 1365 perfd_time_headers (elapsed_time_headers),
1283 perfd_time_firstbyte (elapsed_time_firstbyte), 1366 perfd_time_firstbyte (elapsed_time_firstbyte),
1284 perfd_time_transfer (elapsed_time_transfer)); 1367 perfd_time_transfer (elapsed_time_transfer));
@@ -1290,6 +1373,9 @@ check_http (void)
1290 perfd_time (elapsed_time), 1373 perfd_time (elapsed_time),
1291 perfd_size (page_len)); 1374 perfd_size (page_len));
1292 1375
1376 if (show_body)
1377 xasprintf (&msg, _("%s\n%s"), msg, page);
1378
1293 result = max_state_alt(get_status(elapsed_time, thlds), result); 1379 result = max_state_alt(get_status(elapsed_time, thlds), result);
1294 1380
1295 die (result, "HTTP %s: %s\n", state_text(result), msg); 1381 die (result, "HTTP %s: %s\n", state_text(result), msg);
@@ -1297,7 +1383,94 @@ check_http (void)
1297 return STATE_UNKNOWN; 1383 return STATE_UNKNOWN;
1298} 1384}
1299 1385
1386/* Receivces a pointer to the beginning of the body of a HTTP message
1387 * which is chunked and returns a pointer to a freshly allocated memory
1388 * region containing the unchunked body or NULL if something failed.
1389 * The result must be freed by the caller.
1390 */
1391char *unchunk_content(const char *content) {
1392 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
1393 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
1394 char *result = NULL;
1395 char *start_of_chunk;
1396 char* end_of_chunk;
1397 long size_of_chunk;
1398 const char *pointer = content;
1399 char *endptr;
1400 long length_of_chunk = 0;
1401 size_t overall_size = 0;
1402
1403 while (true) {
1404 size_of_chunk = strtol(pointer, &endptr, 16);
1405 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
1406 // Apparently underflow or overflow, should not happen
1407 if (verbose) {
1408 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
1409 }
1410 return NULL;
1411 }
1412 if (endptr == pointer) {
1413 // Apparently this was not a number
1414 if (verbose) {
1415 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
1416 }
1417 return NULL;
1418 }
1419
1420 // So, we got the length of the chunk
1421 if (*endptr == ';') {
1422 // Chunk extension starts here
1423 while (*endptr != '\r') {
1424 endptr++;
1425 }
1426 }
1427
1428 start_of_chunk = endptr + 2;
1429 end_of_chunk = start_of_chunk + size_of_chunk;
1430 length_of_chunk = (long)(end_of_chunk - start_of_chunk);
1431 pointer = end_of_chunk + 2; //Next number should be here
1432
1433 if (length_of_chunk == 0) {
1434 // Chunk length is 0, so this is the last one
1435 break;
1436 }
1300 1437
1438 overall_size += length_of_chunk;
1439
1440 if (result == NULL) {
1441 // Size of the chunk plus the ending NULL byte
1442 result = (char *)malloc(length_of_chunk +1);
1443 if (result == NULL) {
1444 if (verbose) {
1445 printf("Failed to allocate memory for unchunked body\n");
1446 }
1447 return NULL;
1448 }
1449 } else {
1450 // Enlarge memory to the new size plus the ending NULL byte
1451 void *tmp = realloc(result, overall_size +1);
1452 if (tmp == NULL) {
1453 if (verbose) {
1454 printf("Failed to allocate memory for unchunked body\n");
1455 }
1456 return NULL;
1457 } else {
1458 result = tmp;
1459 }
1460 }
1461
1462 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk);
1463 }
1464
1465 if (overall_size == 0 && result == NULL) {
1466 // We might just have received the end chunk without previous content, so result is never allocated
1467 result = calloc(1, sizeof(char));
1468 // No error handling here, we can only return NULL anyway
1469 } else {
1470 result[overall_size] = '\0';
1471 }
1472 return result;
1473}
1301 1474
1302/* per RFC 2396 */ 1475/* per RFC 2396 */
1303#define URI_HTTP "%5[HTPShtps]" 1476#define URI_HTTP "%5[HTPShtps]"
@@ -1308,7 +1481,9 @@ check_http (void)
1308#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH 1481#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1309#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT 1482#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1310#define HD4 URI_HTTP "://" URI_HOST 1483#define HD4 URI_HTTP "://" URI_HOST
1311#define HD5 URI_PATH 1484/* relative reference redirect like //www.site.org/test https://tools.ietf.org/html/rfc3986 */
1485#define HD5 "//" URI_HOST "/" URI_PATH
1486#define HD6 URI_PATH
1312 1487
1313void 1488void
1314redir (char *pos, char *status_line) 1489redir (char *pos, char *status_line)
@@ -1385,9 +1560,21 @@ redir (char *pos, char *status_line)
1385 use_ssl = server_type_check (type); 1560 use_ssl = server_type_check (type);
1386 i = server_port_check (use_ssl); 1561 i = server_port_check (use_ssl);
1387 } 1562 }
1563 /* URI_HTTP, URI_HOST, URI_PATH */
1564 else if (sscanf (pos, HD5, addr, url) == 2) {
1565 if(use_ssl){
1566 strcpy (type,"https");
1567 }
1568 else{
1569 strcpy (type, server_type);
1570 }
1571 xasprintf (&url, "/%s", url);
1572 use_ssl = server_type_check (type);
1573 i = server_port_check (use_ssl);
1574 }
1388 1575
1389 /* URI_PATH */ 1576 /* URI_PATH */
1390 else if (sscanf (pos, HD5, url) == 1) { 1577 else if (sscanf (pos, HD6, url) == 1) {
1391 /* relative url */ 1578 /* relative url */
1392 if ((url[0] != '/')) { 1579 if ((url[0] != '/')) {
1393 if ((x = strrchr(server_url, '/'))) 1580 if ((x = strrchr(server_url, '/')))
@@ -1418,8 +1605,8 @@ redir (char *pos, char *status_line)
1418 !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) && 1605 !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) &&
1419 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && 1606 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) &&
1420 !strcmp(server_url, url)) 1607 !strcmp(server_url, url))
1421 die (STATE_WARNING, 1608 die (STATE_CRITICAL,
1422 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1609 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1423 type, addr, i, url, (display_html ? "</A>" : "")); 1610 type, addr, i, url, (display_html ? "</A>" : ""));
1424 1611
1425 strcpy (server_type, type); 1612 strcpy (server_type, type);
@@ -1456,13 +1643,13 @@ redir (char *pos, char *status_line)
1456} 1643}
1457 1644
1458 1645
1459int 1646bool
1460server_type_check (const char *type) 1647server_type_check (const char *type)
1461{ 1648{
1462 if (strcmp (type, "https")) 1649 if (strcmp (type, "https"))
1463 return FALSE; 1650 return false;
1464 else 1651 else
1465 return TRUE; 1652 return true;
1466} 1653}
1467 1654
1468int 1655int
@@ -1477,42 +1664,42 @@ server_port_check (int ssl_flag)
1477char *perfd_time (double elapsed_time) 1664char *perfd_time (double elapsed_time)
1478{ 1665{
1479 return fperfdata ("time", elapsed_time, "s", 1666 return fperfdata ("time", elapsed_time, "s",
1480 thlds->warning?TRUE:FALSE, thlds->warning?thlds->warning->end:0, 1667 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1481 thlds->critical?TRUE:FALSE, thlds->critical?thlds->critical->end:0, 1668 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1482 TRUE, 0, TRUE, socket_timeout); 1669 true, 0, true, socket_timeout);
1483} 1670}
1484 1671
1485char *perfd_time_connect (double elapsed_time_connect) 1672char *perfd_time_connect (double elapsed_time_connect)
1486{ 1673{
1487 return fperfdata ("time_connect", elapsed_time_connect, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1674 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1488} 1675}
1489 1676
1490char *perfd_time_ssl (double elapsed_time_ssl) 1677char *perfd_time_ssl (double elapsed_time_ssl)
1491{ 1678{
1492 return fperfdata ("time_ssl", elapsed_time_ssl, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1679 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1493} 1680}
1494 1681
1495char *perfd_time_headers (double elapsed_time_headers) 1682char *perfd_time_headers (double elapsed_time_headers)
1496{ 1683{
1497 return fperfdata ("time_headers", elapsed_time_headers, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1684 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1498} 1685}
1499 1686
1500char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1687char *perfd_time_firstbyte (double elapsed_time_firstbyte)
1501{ 1688{
1502 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1689 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1503} 1690}
1504 1691
1505char *perfd_time_transfer (double elapsed_time_transfer) 1692char *perfd_time_transfer (double elapsed_time_transfer)
1506{ 1693{
1507 return fperfdata ("time_transfer", elapsed_time_transfer, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1694 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1508} 1695}
1509 1696
1510char *perfd_size (int page_len) 1697char *perfd_size (int page_len)
1511{ 1698{
1512 return perfdata ("size", page_len, "B", 1699 return perfdata ("size", page_len, "B",
1513 (min_page_len>0?TRUE:FALSE), min_page_len, 1700 (min_page_len>0?true:false), min_page_len,
1514 (min_page_len>0?TRUE:FALSE), 0, 1701 (min_page_len>0?true:false), 0,
1515 TRUE, 0, FALSE, 0); 1702 true, 0, false, 0);
1516} 1703}
1517 1704
1518void 1705void
@@ -1532,6 +1719,10 @@ print_help (void)
1532 1719
1533 print_usage (); 1720 print_usage ();
1534 1721
1722#ifdef HAVE_SSL
1723 printf (_("In the first form, make an HTTP request."));
1724 printf (_("In the second form, connect to the server and check the TLS certificate."));
1725#endif
1535 printf (_("NOTE: One or both of -H and -I must be specified")); 1726 printf (_("NOTE: One or both of -H and -I must be specified"));
1536 1727
1537 printf ("\n"); 1728 printf ("\n");
@@ -1559,7 +1750,11 @@ print_help (void)
1559 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1750 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1560 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1751 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1561 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); 1752 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1562 printf (" %s\n", _("(when this option is used the URL is not checked.)")); 1753 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
1754 printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
1755 printf (" %s\n", "--continue-after-certificate");
1756 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
1757 printf (" %s\n", _("Does nothing unless -C is used."));
1563 printf (" %s\n", "-J, --client-cert=FILE"); 1758 printf (" %s\n", "-J, --client-cert=FILE");
1564 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1759 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1565 printf (" %s\n", _("to be used in establishing the SSL session")); 1760 printf (" %s\n", _("to be used in establishing the SSL session"));
@@ -1581,7 +1776,7 @@ print_help (void)
1581 printf (" %s\n", _("URL to GET or POST (default: /)")); 1776 printf (" %s\n", _("URL to GET or POST (default: /)"));
1582 printf (" %s\n", "-P, --post=STRING"); 1777 printf (" %s\n", "-P, --post=STRING");
1583 printf (" %s\n", _("URL encoded http POST data")); 1778 printf (" %s\n", _("URL encoded http POST data"));
1584 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 1779 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST)");
1585 printf (" %s\n", _("Set HTTP method.")); 1780 printf (" %s\n", _("Set HTTP method."));
1586 printf (" %s\n", "-N, --no-body"); 1781 printf (" %s\n", "-N, --no-body");
1587 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1782 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
@@ -1611,14 +1806,18 @@ print_help (void)
1611 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1806 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
1612 printf (" %s\n", "-E, --extended-perfdata"); 1807 printf (" %s\n", "-E, --extended-perfdata");
1613 printf (" %s\n", _("Print additional performance data")); 1808 printf (" %s\n", _("Print additional performance data"));
1809 printf (" %s\n", "-B, --show-body");
1810 printf (" %s\n", _("Print body content below status line"));
1614 printf (" %s\n", "-L, --link"); 1811 printf (" %s\n", "-L, --link");
1615 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1812 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1616 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>"); 1813 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1617 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1814 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1618 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1815 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1816 printf (" %s\n", "--max-redirs=INTEGER");
1817 printf (" %s", _("Maximal number of redirects (default: "));
1818 printf ("%d)\n", DEFAULT_MAX_REDIRS);
1619 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 1819 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1620 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 1820 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1621
1622 printf (UT_WARN_CRIT); 1821 printf (UT_WARN_CRIT);
1623 1822
1624 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1823 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
@@ -1668,7 +1867,8 @@ print_help (void)
1668 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 1867 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
1669 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1868 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1670 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1869 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1671 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 1870 printf (" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can set the method used"));
1871 printf (" %s\n", _("inside the proxied connection: -j CONNECT:POST"));
1672 1872
1673#endif 1873#endif
1674 1874
@@ -1685,9 +1885,11 @@ print_usage (void)
1685 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 1885 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1686 printf (" [-J <client certificate file>] [-K <private key>]\n"); 1886 printf (" [-J <client certificate file>] [-K <private key>]\n");
1687 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1887 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1688 printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n"); 1888 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n");
1689 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 1889 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1690 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1890 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1691 printf (" [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]]\n"); 1891 printf (" [-A string] [-k string] [-S <version>] [--sni]\n");
1692 printf (" [-T <content-type>] [-j method]\n"); 1892 printf (" [-T <content-type>] [-j method]\n");
1893 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
1894 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1693} 1895}
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c
index bc7bd44..a1bfe1b 100644
--- a/plugins/check_ldap.c
+++ b/plugins/check_ldap.c
@@ -222,7 +222,7 @@ main (int argc, char *argv[])
222 /* reset the alarm handler */ 222 /* reset the alarm handler */
223 alarm (0); 223 alarm (0);
224 224
225 /* calcutate the elapsed time and compare to thresholds */ 225 /* calculate the elapsed time and compare to thresholds */
226 226
227 microsec = deltime (tv); 227 microsec = deltime (tv);
228 elapsed_time = (double)microsec / 1.0e6; 228 elapsed_time = (double)microsec / 1.0e6;
@@ -432,6 +432,9 @@ validate_arguments ()
432 set_thresholds(&entries_thresholds, 432 set_thresholds(&entries_thresholds,
433 warn_entries, crit_entries); 433 warn_entries, crit_entries);
434 } 434 }
435 if (ld_passwd==NULL)
436 ld_passwd = getenv("LDAP_PASSWORD");
437
435 return OK; 438 return OK;
436} 439}
437 440
@@ -465,7 +468,7 @@ print_help (void)
465 printf (" %s\n", "-D [--bind]"); 468 printf (" %s\n", "-D [--bind]");
466 printf (" %s\n", _("ldap bind DN (if required)")); 469 printf (" %s\n", _("ldap bind DN (if required)"));
467 printf (" %s\n", "-P [--pass]"); 470 printf (" %s\n", "-P [--pass]");
468 printf (" %s\n", _("ldap password (if required)")); 471 printf (" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')"));
469 printf (" %s\n", "-T [--starttls]"); 472 printf (" %s\n", "-T [--starttls]");
470 printf (" %s\n", _("use starttls mechanism introduced in protocol version 3")); 473 printf (" %s\n", _("use starttls mechanism introduced in protocol version 3"));
471 printf (" %s\n", "-S [--ssl]"); 474 printf (" %s\n", "-S [--ssl]");
diff --git a/plugins/check_load.c b/plugins/check_load.c
index b1cc498..313df8a 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -1,40 +1,43 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_load plugin 3* Monitoring check_load plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6* Copyright (c) 1999-2007 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
10* This file contains the check_load plugin 10* This file contains the check_load plugin
11* 11*
12* This plugin tests the current system load average. 12* This plugin tests the current system load average.
13* 13*
14* 14*
15* This program is free software: you can redistribute it and/or modify 15* This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16* it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17* the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18* (at your option) any later version.
19* 19*
20* This program is distributed in the hope that it will be useful, 20* This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21* but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23* GNU General Public License for more details.
24* 24*
25* You should have received a copy of the GNU General Public License 25* You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26* along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27*
28* 28*
29*****************************************************************************/ 29*****************************************************************************/
30 30
31const char *progname = "check_load"; 31const char *progname = "check_load";
32const char *copyright = "1999-2007"; 32const char *copyright = "1999-2022";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "utils.h" 36#include "./runcmd.h"
37#include "popen.h" 37#include "./utils.h"
38#include "./popen.h"
39
40#include <string.h>
38 41
39#ifdef HAVE_SYS_LOADAVG_H 42#ifdef HAVE_SYS_LOADAVG_H
40#include <sys/loadavg.h> 43#include <sys/loadavg.h>
@@ -52,6 +55,9 @@ static int process_arguments (int argc, char **argv);
52static int validate_arguments (void); 55static int validate_arguments (void);
53void print_help (void); 56void print_help (void);
54void print_usage (void); 57void print_usage (void);
58static int print_top_consuming_processes();
59
60static int n_procs_to_show = 0;
55 61
56/* strictly for pretty-print usage in loops */ 62/* strictly for pretty-print usage in loops */
57static const int nums[3] = { 1, 5, 15 }; 63static const int nums[3] = { 1, 5, 15 };
@@ -64,7 +70,7 @@ double cload[3] = { 0.0, 0.0, 0.0 };
64#define la15 la[2] 70#define la15 la[2]
65 71
66char *status_line; 72char *status_line;
67int take_into_account_cpus = 0; 73bool take_into_account_cpus = false;
68 74
69static void 75static void
70get_threshold(char *arg, double *th) 76get_threshold(char *arg, double *th)
@@ -97,11 +103,11 @@ get_threshold(char *arg, double *th)
97int 103int
98main (int argc, char **argv) 104main (int argc, char **argv)
99{ 105{
100 int result; 106 int result = -1;
101 int i; 107 int i;
102 long numcpus; 108 long numcpus;
103 109
104 double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about unitialized arrays */ 110 double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
105#ifndef HAVE_GETLOADAVG 111#ifndef HAVE_GETLOADAVG
106 char input_buffer[MAX_INPUT_BUFFER]; 112 char input_buffer[MAX_INPUT_BUFFER];
107# ifdef HAVE_PROC_LOADAVG 113# ifdef HAVE_PROC_LOADAVG
@@ -160,7 +166,7 @@ main (int argc, char **argv)
160 sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15); 166 sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
161 } 167 }
162 else { 168 else {
163 printf (_("could not parse load from uptime %s: %s\n"), PATH_TO_UPTIME, result); 169 printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
164 return STATE_UNKNOWN; 170 return STATE_UNKNOWN;
165 } 171 }
166 172
@@ -172,13 +178,6 @@ main (int argc, char **argv)
172# endif 178# endif
173#endif 179#endif
174 180
175 if (take_into_account_cpus == 1) {
176 if ((numcpus = GET_NUMBER_OF_CPUS()) > 0) {
177 la[0] = la[0] / numcpus;
178 la[1] = la[1] / numcpus;
179 la[2] = la[2] / numcpus;
180 }
181 }
182 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) { 181 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
183#ifdef HAVE_GETLOADAVG 182#ifdef HAVE_GETLOADAVG
184 printf (_("Error in getloadavg()\n")); 183 printf (_("Error in getloadavg()\n"));
@@ -196,20 +195,54 @@ main (int argc, char **argv)
196 result = STATE_OK; 195 result = STATE_OK;
197 196
198 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); 197 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15);
198 xasprintf(&status_line, ("total %s"), status_line);
199
200
201 double scaled_la[3] = { 0.0, 0.0, 0.0 };
202 bool is_using_scaled_load_values = false;
203
204 if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) {
205 is_using_scaled_load_values = true;
206
207 scaled_la[0] = la[0] / numcpus;
208 scaled_la[1] = la[1] / numcpus;
209 scaled_la[2] = la[2] / numcpus;
210
211 char *tmp = NULL;
212 xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]);
213 xasprintf(&status_line, "scaled %s - %s", tmp, status_line);
214 }
199 215
200 for(i = 0; i < 3; i++) { 216 for(i = 0; i < 3; i++) {
201 if(la[i] > cload[i]) { 217 if (is_using_scaled_load_values) {
202 result = STATE_CRITICAL; 218 if(scaled_la[i] > cload[i]) {
203 break; 219 result = STATE_CRITICAL;
220 break;
221 }
222 else if(scaled_la[i] > wload[i]) result = STATE_WARNING;
223 } else {
224 if(la[i] > cload[i]) {
225 result = STATE_CRITICAL;
226 break;
227 }
228 else if(la[i] > wload[i]) result = STATE_WARNING;
204 } 229 }
205 else if(la[i] > wload[i]) result = STATE_WARNING;
206 } 230 }
207 231
208 printf("%s - %s|", state_text(result), status_line); 232 printf("LOAD %s - %s|", state_text(result), status_line);
209 for(i = 0; i < 3; i++) 233 for(i = 0; i < 3; i++) {
210 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]); 234 if (is_using_scaled_load_values) {
235 printf("load%d=%.3f;;;0; ", nums[i], la[i]);
236 printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]);
237 } else {
238 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
239 }
240 }
211 241
212 putchar('\n'); 242 putchar('\n');
243 if (n_procs_to_show > 0) {
244 print_top_consuming_processes();
245 }
213 return result; 246 return result;
214} 247}
215 248
@@ -227,6 +260,7 @@ process_arguments (int argc, char **argv)
227 {"percpu", no_argument, 0, 'r'}, 260 {"percpu", no_argument, 0, 'r'},
228 {"version", no_argument, 0, 'V'}, 261 {"version", no_argument, 0, 'V'},
229 {"help", no_argument, 0, 'h'}, 262 {"help", no_argument, 0, 'h'},
263 {"procs-to-show", required_argument, 0, 'n'},
230 {0, 0, 0, 0} 264 {0, 0, 0, 0}
231 }; 265 };
232 266
@@ -234,7 +268,7 @@ process_arguments (int argc, char **argv)
234 return ERROR; 268 return ERROR;
235 269
236 while (1) { 270 while (1) {
237 c = getopt_long (argc, argv, "Vhrc:w:", longopts, &option); 271 c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option);
238 272
239 if (c == -1 || c == EOF) 273 if (c == -1 || c == EOF)
240 break; 274 break;
@@ -247,7 +281,7 @@ process_arguments (int argc, char **argv)
247 get_threshold(optarg, cload); 281 get_threshold(optarg, cload);
248 break; 282 break;
249 case 'r': /* Divide load average by number of CPUs */ 283 case 'r': /* Divide load average by number of CPUs */
250 take_into_account_cpus = 1; 284 take_into_account_cpus = true;
251 break; 285 break;
252 case 'V': /* version */ 286 case 'V': /* version */
253 print_revision (progname, NP_VERSION); 287 print_revision (progname, NP_VERSION);
@@ -255,6 +289,9 @@ process_arguments (int argc, char **argv)
255 case 'h': /* help */ 289 case 'h': /* help */
256 print_help (); 290 print_help ();
257 exit (STATE_UNKNOWN); 291 exit (STATE_UNKNOWN);
292 case 'n':
293 n_procs_to_show = atoi(optarg);
294 break;
258 case '?': /* help */ 295 case '?': /* help */
259 usage5 (); 296 usage5 ();
260 } 297 }
@@ -278,7 +315,6 @@ process_arguments (int argc, char **argv)
278} 315}
279 316
280 317
281
282static int 318static int
283validate_arguments (void) 319validate_arguments (void)
284{ 320{
@@ -299,7 +335,6 @@ validate_arguments (void)
299} 335}
300 336
301 337
302
303void 338void
304print_help (void) 339print_help (void)
305{ 340{
@@ -310,7 +345,7 @@ print_help (void)
310 345
311 printf (_("This plugin tests the current system load average.")); 346 printf (_("This plugin tests the current system load average."));
312 347
313 printf ("\n\n"); 348 printf ("\n\n");
314 349
315 print_usage (); 350 print_usage ();
316 351
@@ -318,12 +353,15 @@ print_help (void)
318 printf (UT_EXTRA_OPTS); 353 printf (UT_EXTRA_OPTS);
319 354
320 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15"); 355 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
321 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn")); 356 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
322 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15"); 357 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
323 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn")); 358 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
324 printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\"")); 359 printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
325 printf (" %s\n", "-r, --percpu"); 360 printf (" %s\n", "-r, --percpu");
326 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)")); 361 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
362 printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
363 printf (" %s\n", _("Number of processes to show when printing the top consuming processes."));
364 printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
327 365
328 printf (UT_SUPPORT); 366 printf (UT_SUPPORT);
329} 367}
@@ -331,6 +369,49 @@ print_help (void)
331void 369void
332print_usage (void) 370print_usage (void)
333{ 371{
334 printf ("%s\n", _("Usage:")); 372 printf ("%s\n", _("Usage:"));
335 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15\n", progname); 373 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
374}
375
376#ifdef PS_USES_PROCPCPU
377int cmpstringp(const void *p1, const void *p2) {
378 int procuid = 0;
379 int procpid = 0;
380 int procppid = 0;
381 int procvsz = 0;
382 int procrss = 0;
383 float procpcpu = 0;
384 char procstat[8];
385#ifdef PS_USES_PROCETIME
386 char procetime[MAX_INPUT_BUFFER];
387#endif /* PS_USES_PROCETIME */
388 char procprog[MAX_INPUT_BUFFER];
389 int pos;
390 sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST);
391 float procpcpu1 = procpcpu;
392 sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST);
393 return procpcpu1 < procpcpu;
394}
395#endif /* PS_USES_PROCPCPU */
396
397static int print_top_consuming_processes() {
398 int i = 0;
399 struct output chld_out, chld_err;
400 if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){
401 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
402 return STATE_UNKNOWN;
403 }
404 if (chld_out.lines < 2) {
405 fprintf(stderr, _("some error occurred getting procs list.\n"));
406 return STATE_UNKNOWN;
407 }
408#ifdef PS_USES_PROCPCPU
409 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp);
410#endif /* PS_USES_PROCPCPU */
411 int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1)
412 ? (int)chld_out.lines : n_procs_to_show + 1;
413 for (i = 0; i < lines_to_show; i += 1) {
414 printf("%s\n", chld_out.line[i]);
415 }
416 return OK;
336} 417}
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index 5773afd..7d85554 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -34,7 +34,7 @@ const char *progname = "check_mysql";
34const char *copyright = "1999-2011"; 34const char *copyright = "1999-2011";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#define SLAVERESULTSIZE 70 37#define SLAVERESULTSIZE 96
38 38
39#include "common.h" 39#include "common.h"
40#include "utils.h" 40#include "utils.h"
@@ -89,6 +89,8 @@ static const char *metric_counter[LENGTH_METRIC_COUNTER] = {
89 "Uptime" 89 "Uptime"
90}; 90};
91 91
92#define MYSQLDUMP_THREADS_QUERY "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'"
93
92thresholds *my_threshold = NULL; 94thresholds *my_threshold = NULL;
93 95
94int process_arguments (int, char **); 96int process_arguments (int, char **);
@@ -108,7 +110,7 @@ main (int argc, char **argv)
108 110
109 char *result = NULL; 111 char *result = NULL;
110 char *error = NULL; 112 char *error = NULL;
111 char slaveresult[SLAVERESULTSIZE]; 113 char slaveresult[SLAVERESULTSIZE] = { 0 };
112 char* perf; 114 char* perf;
113 115
114 perf = strdup (""); 116 perf = strdup ("");
@@ -138,7 +140,10 @@ main (int argc, char **argv)
138 mysql_ssl_set(&mysql,key,cert,ca_cert,ca_dir,ciphers); 140 mysql_ssl_set(&mysql,key,cert,ca_cert,ca_dir,ciphers);
139 /* establish a connection to the server and error checking */ 141 /* establish a connection to the server and error checking */
140 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) { 142 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) {
141 if (ignore_auth && mysql_errno (&mysql) == ER_ACCESS_DENIED_ERROR) 143 /* Depending on internally-selected auth plugin MySQL might return */
144 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
145 /* Semantically these errors are the same. */
146 if (ignore_auth && (mysql_errno (&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno (&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR))
142 { 147 {
143 printf("MySQL OK - Version: %s (protocol %d)\n", 148 printf("MySQL OK - Version: %s (protocol %d)\n",
144 mysql_get_server_info(&mysql), 149 mysql_get_server_info(&mysql),
@@ -275,11 +280,30 @@ main (int argc, char **argv)
275 /* Save slave status in slaveresult */ 280 /* Save slave status in slaveresult */
276 snprintf (slaveresult, SLAVERESULTSIZE, "Slave IO: %s Slave SQL: %s Seconds Behind Master: %s", row[slave_io_field], row[slave_sql_field], seconds_behind_field!=-1?row[seconds_behind_field]:"Unknown"); 281 snprintf (slaveresult, SLAVERESULTSIZE, "Slave IO: %s Slave SQL: %s Seconds Behind Master: %s", row[slave_io_field], row[slave_sql_field], seconds_behind_field!=-1?row[seconds_behind_field]:"Unknown");
277 282
278 /* Raise critical error if SQL THREAD or IO THREAD are stopped */ 283 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */
279 if (strcmp (row[slave_io_field], "Yes") != 0 || strcmp (row[slave_sql_field], "Yes") != 0) { 284 if (strcmp (row[slave_io_field], "Yes") != 0 || strcmp (row[slave_sql_field], "Yes") != 0) {
280 mysql_free_result (res); 285 MYSQL_RES *res_mysqldump;
281 mysql_close (&mysql); 286 MYSQL_ROW row_mysqldump;
282 die (STATE_CRITICAL, "%s\n", slaveresult); 287 unsigned int mysqldump_threads = 0;
288
289 if (mysql_query (&mysql, MYSQLDUMP_THREADS_QUERY) == 0) {
290 /* store the result */
291 if ( (res_mysqldump = mysql_store_result (&mysql)) != NULL) {
292 if (mysql_num_rows(res_mysqldump) == 1) {
293 if ( (row_mysqldump = mysql_fetch_row (res_mysqldump)) != NULL) {
294 mysqldump_threads = atoi(row_mysqldump[0]);
295 }
296 }
297 /* free the result */
298 mysql_free_result (res_mysqldump);
299 }
300 mysql_close (&mysql);
301 }
302 if (mysqldump_threads == 0) {
303 die (STATE_CRITICAL, "%s\n", slaveresult);
304 } else {
305 strncat(slaveresult, " Mysqldump: in progress", SLAVERESULTSIZE-1);
306 }
283 } 307 }
284 308
285 if (verbose >=3) { 309 if (verbose >=3) {
@@ -291,7 +315,7 @@ main (int argc, char **argv)
291 } 315 }
292 316
293 /* Check Seconds Behind against threshold */ 317 /* Check Seconds Behind against threshold */
294 if ((seconds_behind_field != -1) && (strcmp (row[seconds_behind_field], "NULL") != 0)) { 318 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp (row[seconds_behind_field], "NULL") != 0)) {
295 double value = atof(row[seconds_behind_field]); 319 double value = atof(row[seconds_behind_field]);
296 int status; 320 int status;
297 321
@@ -379,6 +403,9 @@ process_arguments (int argc, char **argv)
379 if (is_host (optarg)) { 403 if (is_host (optarg)) {
380 db_host = optarg; 404 db_host = optarg;
381 } 405 }
406 else if (*optarg == '/') {
407 db_socket = optarg;
408 }
382 else { 409 else {
383 usage2 (_("Invalid hostname/address"), optarg); 410 usage2 (_("Invalid hostname/address"), optarg);
384 } 411 }
@@ -548,7 +575,7 @@ print_help (void)
548 printf (" %s\n", _("Exit with CRITICAL status if slave server is more then INTEGER seconds")); 575 printf (" %s\n", _("Exit with CRITICAL status if slave server is more then INTEGER seconds"));
549 printf (" %s\n", _("behind master")); 576 printf (" %s\n", _("behind master"));
550 printf (" %s\n", "-l, --ssl"); 577 printf (" %s\n", "-l, --ssl");
551 printf (" %s\n", _("Use ssl encryptation")); 578 printf (" %s\n", _("Use ssl encryption"));
552 printf (" %s\n", "-C, --ca-cert=STRING"); 579 printf (" %s\n", "-C, --ca-cert=STRING");
553 printf (" %s\n", _("Path to CA signing the cert")); 580 printf (" %s\n", _("Path to CA signing the cert"));
554 printf (" %s\n", "-a, --cert=STRING"); 581 printf (" %s\n", "-a, --cert=STRING");
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c
index 49a14dd..ac2fb15 100644
--- a/plugins/check_mysql_query.c
+++ b/plugins/check_mysql_query.c
@@ -136,18 +136,18 @@ main (int argc, char **argv)
136 die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); 136 die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error);
137 } 137 }
138 138
139 /* free the result */
140 mysql_free_result (res);
141
142 /* close the connection */
143 mysql_close (&mysql);
144
145 if (! is_numeric(row[0])) { 139 if (! is_numeric(row[0])) {
146 die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); 140 die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]);
147 } 141 }
148 142
149 value = strtod(row[0], NULL); 143 value = strtod(row[0], NULL);
150 144
145 /* free the result */
146 mysql_free_result (res);
147
148 /* close the connection */
149 mysql_close (&mysql);
150
151 if (verbose >= 3) 151 if (verbose >= 3)
152 printf("mysql result: %f\n", value); 152 printf("mysql result: %f\n", value);
153 153
diff --git a/plugins/check_nt.c b/plugins/check_nt.c
index 59c135d..d73d83c 100644
--- a/plugins/check_nt.c
+++ b/plugins/check_nt.c
@@ -341,7 +341,7 @@ int main(int argc, char **argv){
341 341
342 2) If the counter you're going to measure is percent-based, the code will detect 342 2) If the counter you're going to measure is percent-based, the code will detect
343 the percent sign in its name and will attribute minimum (0%) and maximum (100%) 343 the percent sign in its name and will attribute minimum (0%) and maximum (100%)
344 values automagically, as well the ¨%" sign to graph units. 344 values automagically, as well the "%" sign to graph units.
345 345
346 3) OTOH, if the counter is "absolute", you'll have to provide the following 346 3) OTOH, if the counter is "absolute", you'll have to provide the following
347 the counter unit - that is, the dimensions of the counter you're getting. Examples: 347 the counter unit - that is, the dimensions of the counter you're getting. Examples:
diff --git a/plugins/check_ntp.c b/plugins/check_ntp.c
index 914b40c..3614650 100644
--- a/plugins/check_ntp.c
+++ b/plugins/check_ntp.c
@@ -10,7 +10,7 @@
10* 10*
11* This file contains the check_ntp plugin 11* This file contains the check_ntp plugin
12* 12*
13* This plugin to check ntp servers independant of any commandline 13* This plugin to check ntp servers independent of any commandline
14* programs or external libraries. 14* programs or external libraries.
15* 15*
16* 16*
@@ -79,7 +79,7 @@ typedef struct {
79/* this structure holds data about results from querying offset from a peer */ 79/* this structure holds data about results from querying offset from a peer */
80typedef struct { 80typedef struct {
81 time_t waiting; /* ts set when we started waiting for a response */ 81 time_t waiting; /* ts set when we started waiting for a response */
82 int num_responses; /* number of successfully recieved responses */ 82 int num_responses; /* number of successfully received responses */
83 uint8_t stratum; /* copied verbatim from the ntp_message */ 83 uint8_t stratum; /* copied verbatim from the ntp_message */
84 double rtdelay; /* converted from the ntp_message */ 84 double rtdelay; /* converted from the ntp_message */
85 double rtdisp; /* converted from the ntp_message */ 85 double rtdisp; /* converted from the ntp_message */
@@ -100,7 +100,7 @@ typedef struct {
100 /* NB: not necessarily NULL terminated! */ 100 /* NB: not necessarily NULL terminated! */
101} ntp_control_message; 101} ntp_control_message;
102 102
103/* this is an association/status-word pair found in control packet reponses */ 103/* this is an association/status-word pair found in control packet responses */
104typedef struct { 104typedef struct {
105 uint16_t assoc; 105 uint16_t assoc;
106 uint16_t status; 106 uint16_t status;
@@ -355,7 +355,7 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
355 * - we also "manually" handle resolving host names and connecting, because 355 * - we also "manually" handle resolving host names and connecting, because
356 * we have to do it in a way that our lazy macros don't handle currently :( */ 356 * we have to do it in a way that our lazy macros don't handle currently :( */
357double offset_request(const char *host, int *status){ 357double offset_request(const char *host, int *status){
358 int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0; 358 int i=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
359 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1; 359 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1;
360 time_t now_time=0, start_ts=0; 360 time_t now_time=0, start_ts=0;
361 ntp_message *req=NULL; 361 ntp_message *req=NULL;
@@ -488,7 +488,7 @@ double offset_request(const char *host, int *status){
488 /* cleanup */ 488 /* cleanup */
489 /* FIXME: Not closing the socket to avoid re-use of the local port 489 /* FIXME: Not closing the socket to avoid re-use of the local port
490 * which can cause old NTP packets to be read instead of NTP control 490 * which can cause old NTP packets to be read instead of NTP control
491 * pactets in jitter_request(). THERE MUST BE ANOTHER WAY... 491 * packets in jitter_request(). THERE MUST BE ANOTHER WAY...
492 * for(j=0; j<num_hosts; j++){ close(socklist[j]); } */ 492 * for(j=0; j<num_hosts; j++){ close(socklist[j]); } */
493 free(socklist); 493 free(socklist);
494 free(ufds); 494 free(ufds);
@@ -512,7 +512,7 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
512} 512}
513 513
514/* XXX handle responses with the error bit set */ 514/* XXX handle responses with the error bit set */
515double jitter_request(const char *host, int *status){ 515double jitter_request(int *status){
516 int conn=-1, i, npeers=0, num_candidates=0, syncsource_found=0; 516 int conn=-1, i, npeers=0, num_candidates=0, syncsource_found=0;
517 int run=0, min_peer_sel=PEER_INCLUDED, num_selected=0, num_valid=0; 517 int run=0, min_peer_sel=PEER_INCLUDED, num_selected=0, num_valid=0;
518 int peers_size=0, peer_offset=0; 518 int peers_size=0, peer_offset=0;
@@ -575,7 +575,7 @@ double jitter_request(const char *host, int *status){
575 } 575 }
576 } 576 }
577 } 577 }
578 if(verbose) printf("%d candiate peers available\n", num_candidates); 578 if(verbose) printf("%d candidate peers available\n", num_candidates);
579 if(verbose && syncsource_found) printf("synchronization source found\n"); 579 if(verbose && syncsource_found) printf("synchronization source found\n");
580 if(! syncsource_found){ 580 if(! syncsource_found){
581 *status = STATE_UNKNOWN; 581 *status = STATE_UNKNOWN;
@@ -597,7 +597,7 @@ double jitter_request(const char *host, int *status){
597 /* By spec, putting the variable name "jitter" in the request 597 /* By spec, putting the variable name "jitter" in the request
598 * should cause the server to provide _only_ the jitter value. 598 * should cause the server to provide _only_ the jitter value.
599 * thus reducing net traffic, guaranteeing us only a single 599 * thus reducing net traffic, guaranteeing us only a single
600 * datagram in reply, and making intepretation much simpler 600 * datagram in reply, and making interpretation much simpler
601 */ 601 */
602 /* Older servers doesn't know what jitter is, so if we get an 602 /* Older servers doesn't know what jitter is, so if we get an
603 * error on the first pass we redo it with "dispersion" */ 603 * error on the first pass we redo it with "dispersion" */
@@ -803,7 +803,7 @@ int main(int argc, char *argv[]){
803 * (for example) will result in an error 803 * (for example) will result in an error
804 */ 804 */
805 if(do_jitter){ 805 if(do_jitter){
806 jitter=jitter_request(server_address, &jitter_result); 806 jitter=jitter_request(&jitter_result);
807 result = max_state_alt(result, get_status(jitter, jitter_thresholds)); 807 result = max_state_alt(result, get_status(jitter, jitter_thresholds));
808 /* -1 indicates that we couldn't calculate the jitter 808 /* -1 indicates that we couldn't calculate the jitter
809 * Only overrides STATE_OK from the offset */ 809 * Only overrides STATE_OK from the offset */
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index 6842842..49cb100 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -86,7 +86,7 @@ typedef struct {
86 /* NB: not necessarily NULL terminated! */ 86 /* NB: not necessarily NULL terminated! */
87} ntp_control_message; 87} ntp_control_message;
88 88
89/* this is an association/status-word pair found in control packet reponses */ 89/* this is an association/status-word pair found in control packet responses */
90typedef struct { 90typedef struct {
91 uint16_t assoc; 91 uint16_t assoc;
92 uint16_t status; 92 uint16_t status;
@@ -189,7 +189,7 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
189} 189}
190 190
191/* This function does all the actual work; roughly here's what it does 191/* This function does all the actual work; roughly here's what it does
192 * beside setting the offest, jitter and stratum passed as argument: 192 * beside setting the offset, jitter and stratum passed as argument:
193 * - offset can be negative, so if it cannot get the offset, offset_result 193 * - offset can be negative, so if it cannot get the offset, offset_result
194 * is set to UNKNOWN, otherwise OK. 194 * is set to UNKNOWN, otherwise OK.
195 * - jitter and stratum are set to -1 if they cannot be retrieved so any 195 * - jitter and stratum are set to -1 if they cannot be retrieved so any
@@ -199,7 +199,7 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
199 * status is pretty much useless as syncsource_found is a global variable 199 * status is pretty much useless as syncsource_found is a global variable
200 * used later in main to check is the server was synchronized. It works 200 * used later in main to check is the server was synchronized. It works
201 * so I left it alone */ 201 * so I left it alone */
202int ntp_request(const char *host, double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers){ 202int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers){
203 int conn=-1, i, npeers=0, num_candidates=0; 203 int conn=-1, i, npeers=0, num_candidates=0;
204 double tmp_offset = 0; 204 double tmp_offset = 0;
205 int min_peer_sel=PEER_INCLUDED; 205 int min_peer_sel=PEER_INCLUDED;
@@ -306,7 +306,7 @@ int ntp_request(const char *host, double *offset, int *offset_result, double *ji
306 /* Putting the wanted variable names in the request 306 /* Putting the wanted variable names in the request
307 * cause the server to provide _only_ the requested values. 307 * cause the server to provide _only_ the requested values.
308 * thus reducing net traffic, guaranteeing us only a single 308 * thus reducing net traffic, guaranteeing us only a single
309 * datagram in reply, and making intepretation much simpler 309 * datagram in reply, and making interpretation much simpler
310 */ 310 */
311 /* Older servers doesn't know what jitter is, so if we get an 311 /* Older servers doesn't know what jitter is, so if we get an
312 * error on the first pass we redo it with "dispersion" */ 312 * error on the first pass we redo it with "dispersion" */
@@ -585,8 +585,8 @@ int main(int argc, char *argv[]){
585 /* set socket timeout */ 585 /* set socket timeout */
586 alarm (socket_timeout); 586 alarm (socket_timeout);
587 587
588 /* This returns either OK or WARNING (See comment preceeding ntp_request) */ 588 /* This returns either OK or WARNING (See comment preceding ntp_request) */
589 result = ntp_request(server_address, &offset, &offset_result, &jitter, &stratum, &num_truechimers); 589 result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers);
590 590
591 if(offset_result == STATE_UNKNOWN) { 591 if(offset_result == STATE_UNKNOWN) {
592 /* if there's no sync peer (this overrides ntp_request output): */ 592 /* if there's no sync peer (this overrides ntp_request output): */
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index 391b2df..46cc604 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -81,7 +81,7 @@ typedef struct {
81/* this structure holds data about results from querying offset from a peer */ 81/* this structure holds data about results from querying offset from a peer */
82typedef struct { 82typedef struct {
83 time_t waiting; /* ts set when we started waiting for a response */ 83 time_t waiting; /* ts set when we started waiting for a response */
84 int num_responses; /* number of successfully recieved responses */ 84 int num_responses; /* number of successfully received responses */
85 uint8_t stratum; /* copied verbatim from the ntp_message */ 85 uint8_t stratum; /* copied verbatim from the ntp_message */
86 double rtdelay; /* converted from the ntp_message */ 86 double rtdelay; /* converted from the ntp_message */
87 double rtdisp; /* converted from the ntp_message */ 87 double rtdisp; /* converted from the ntp_message */
diff --git a/plugins/check_nwstat.c b/plugins/check_nwstat.c
index e7e8de0..3c9d23e 100644
--- a/plugins/check_nwstat.c
+++ b/plugins/check_nwstat.c
@@ -1668,7 +1668,7 @@ void print_help(void)
1668 1668
1669 printf ("\n"); 1669 printf ("\n");
1670 printf ("%s\n", _("Notes:")); 1670 printf ("%s\n", _("Notes:"));
1671 printf (" %s\n", _("- This plugin requres that the MRTGEXT.NLM file from James Drews' MRTG")); 1671 printf (" %s\n", _("- This plugin requires that the MRTGEXT.NLM file from James Drews' MRTG"));
1672 printf (" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check.")); 1672 printf (" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check."));
1673 printf (" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)")); 1673 printf (" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)"));
1674 printf (" %s\n", _("- Values for critical thresholds should be lower than warning thresholds")); 1674 printf (" %s\n", _("- Values for critical thresholds should be lower than warning thresholds"));
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 5cd4709..6199033 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -34,6 +34,7 @@ const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
36#include "utils.h" 36#include "utils.h"
37#include "utils_cmd.h"
37 38
38#include "netutils.h" 39#include "netutils.h"
39#include <libpq-fe.h> 40#include <libpq-fe.h>
@@ -68,7 +69,6 @@ int process_arguments (int, char **);
68int validate_arguments (void); 69int validate_arguments (void);
69void print_usage (void); 70void print_usage (void);
70void print_help (void); 71void print_help (void);
71int is_pg_dbname (char *);
72int is_pg_logname (char *); 72int is_pg_logname (char *);
73int do_query (PGconn *, char *); 73int do_query (PGconn *, char *);
74 74
@@ -84,6 +84,8 @@ char *pgparams = NULL;
84double twarn = (double)DEFAULT_WARN; 84double twarn = (double)DEFAULT_WARN;
85double tcrit = (double)DEFAULT_CRIT; 85double tcrit = (double)DEFAULT_CRIT;
86char *pgquery = NULL; 86char *pgquery = NULL;
87#define OPTID_QUERYNAME -1000
88char *pgqueryname = NULL;
87char *query_warning = NULL; 89char *query_warning = NULL;
88char *query_critical = NULL; 90char *query_critical = NULL;
89thresholds *qthresholds = NULL; 91thresholds *qthresholds = NULL;
@@ -91,7 +93,7 @@ int verbose = 0;
91 93
92/****************************************************************************** 94/******************************************************************************
93 95
94The (psuedo?)literate programming XML is contained within \@\@\- <XML> \-\@\@ 96The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
95tags in the comments. With in the tags, the XML is assembled sequentially. 97tags in the comments. With in the tags, the XML is assembled sequentially.
96You can define entities in tags. You also have all the #defines available as 98You can define entities in tags. You also have all the #defines available as
97entities. 99entities.
@@ -284,6 +286,7 @@ process_arguments (int argc, char **argv)
284 {"database", required_argument, 0, 'd'}, 286 {"database", required_argument, 0, 'd'},
285 {"option", required_argument, 0, 'o'}, 287 {"option", required_argument, 0, 'o'},
286 {"query", required_argument, 0, 'q'}, 288 {"query", required_argument, 0, 'q'},
289 {"queryname", required_argument, 0, OPTID_QUERYNAME},
287 {"query_critical", required_argument, 0, 'C'}, 290 {"query_critical", required_argument, 0, 'C'},
288 {"query_warning", required_argument, 0, 'W'}, 291 {"query_warning", required_argument, 0, 'W'},
289 {"verbose", no_argument, 0, 'v'}, 292 {"verbose", no_argument, 0, 'v'},
@@ -343,10 +346,10 @@ process_arguments (int argc, char **argv)
343 pgport = optarg; 346 pgport = optarg;
344 break; 347 break;
345 case 'd': /* database name */ 348 case 'd': /* database name */
346 if (!is_pg_dbname (optarg)) /* checks length and valid chars */ 349 if (strlen(optarg) >= NAMEDATALEN) {
347 usage2 (_("Database name is not valid"), optarg); 350 usage2 (_("Database name exceeds the maximum length"), optarg);
348 else /* we know length, and know optarg is terminated, so us strcpy */ 351 }
349 strcpy (dbName, optarg); 352 snprintf(dbName, NAMEDATALEN, "%s", optarg);
350 break; 353 break;
351 case 'l': /* login name */ 354 case 'l': /* login name */
352 if (!is_pg_logname (optarg)) 355 if (!is_pg_logname (optarg))
@@ -367,6 +370,9 @@ process_arguments (int argc, char **argv)
367 case 'q': 370 case 'q':
368 pgquery = optarg; 371 pgquery = optarg;
369 break; 372 break;
373 case OPTID_QUERYNAME:
374 pgqueryname = optarg;
375 break;
370 case 'v': 376 case 'v':
371 verbose++; 377 verbose++;
372 break; 378 break;
@@ -407,45 +413,6 @@ validate_arguments ()
407 return OK; 413 return OK;
408} 414}
409 415
410
411/******************************************************************************
412
413@@-
414<sect3>
415<title>is_pg_dbname</title>
416
417<para>&PROTO_is_pg_dbname;</para>
418
419<para>Given a database name, this function returns TRUE if the string
420is a valid PostgreSQL database name, and returns false if it is
421not.</para>
422
423<para>Valid PostgreSQL database names are less than &NAMEDATALEN;
424characters long and consist of letters, numbers, and underscores. The
425first character cannot be a number, however.</para>
426
427</sect3>
428-@@
429******************************************************************************/
430
431
432
433int
434is_pg_dbname (char *dbname)
435{
436 char txt[NAMEDATALEN];
437 char tmp[NAMEDATALEN];
438 if (strlen (dbname) > NAMEDATALEN - 1)
439 return (FALSE);
440 strncpy (txt, dbname, NAMEDATALEN - 1);
441 txt[NAMEDATALEN - 1] = 0;
442 if (sscanf (txt, "%[_a-zA-Z]%[^_a-zA-Z0-9-]", tmp, tmp) == 1)
443 return (TRUE);
444 if (sscanf (txt, "%[_a-zA-Z]%[_a-zA-Z0-9-]%[^_a-zA-Z0-9-]", tmp, tmp, tmp) ==
445 2) return (TRUE);
446 return (FALSE);
447}
448
449/** 416/**
450 417
451the tango program should eventually create an entity here based on the 418the tango program should eventually create an entity here based on the
@@ -528,6 +495,9 @@ print_help (void)
528 495
529 printf (" %s\n", "-q, --query=STRING"); 496 printf (" %s\n", "-q, --query=STRING");
530 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 497 printf (" %s\n", _("SQL query to run. Only first column in first row will be read"));
498 printf (" %s\n", "--queryname=STRING");
499 printf (" %s\n", _("A name for the query, this string is used instead of the query"));
500 printf (" %s\n", _("in the long output of the plugin"));
531 printf (" %s\n", "-W, --query-warning=RANGE"); 501 printf (" %s\n", "-W, --query-warning=RANGE");
532 printf (" %s\n", _("SQL query value to result in warning status (double)")); 502 printf (" %s\n", _("SQL query value to result in warning status (double)"));
533 printf (" %s\n", "-C, --query-critical=RANGE"); 503 printf (" %s\n", "-C, --query-critical=RANGE");
@@ -547,7 +517,10 @@ print_help (void)
547 printf (" %s\n", _("connecting to the server. The result from the query has to be numeric.")); 517 printf (" %s\n", _("connecting to the server. The result from the query has to be numeric."));
548 printf (" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); 518 printf (" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
549 printf (" %s\n", _("of the last command is taken into account only. The value of the first")); 519 printf (" %s\n", _("of the last command is taken into account only. The value of the first"));
550 printf (" %s\n\n", _("column in the first row is used as the check result.")); 520 printf (" %s\n", _("column in the first row is used as the check result. If a second column is"));
521 printf (" %s\n", _("present in the result set, this is added to the plugin output with a"));
522 printf (" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system"));
523 printf (" %s\n\n", _("executing the plugin."));
551 524
552 printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); 525 printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
553 printf (" %s\n\n", _("for details about how to access internal statistics of the database server.")); 526 printf (" %s\n\n", _("for details about how to access internal statistics of the database server."));
@@ -587,6 +560,7 @@ do_query (PGconn *conn, char *query)
587 PGresult *res; 560 PGresult *res;
588 561
589 char *val_str; 562 char *val_str;
563 char *extra_info;
590 double value; 564 double value;
591 565
592 char *endptr = NULL; 566 char *endptr = NULL;
@@ -641,10 +615,22 @@ do_query (PGconn *conn, char *query)
641 : (my_status == STATE_CRITICAL) 615 : (my_status == STATE_CRITICAL)
642 ? _("CRITICAL") 616 ? _("CRITICAL")
643 : _("UNKNOWN")); 617 : _("UNKNOWN"));
644 printf (_("'%s' returned %f"), query, value); 618 if(pgqueryname) {
619 printf (_("%s returned %f"), pgqueryname, value);
620 }
621 else {
622 printf (_("'%s' returned %f"), query, value);
623 }
624
645 printf ("|query=%f;%s;%s;;\n", value, 625 printf ("|query=%f;%s;%s;;\n", value,
646 query_warning ? query_warning : "", 626 query_warning ? query_warning : "",
647 query_critical ? query_critical : ""); 627 query_critical ? query_critical : "");
628 if (PQnfields (res) > 1) {
629 extra_info = PQgetvalue (res, 0, 1);
630 if (extra_info != NULL) {
631 printf ("Extra Info: %s\n", extra_info);
632 }
633 }
648 return my_status; 634 return my_status;
649} 635}
650 636
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 423ecbe..741f732 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -37,6 +37,8 @@ const char *email = "devel@monitoring-plugins.org";
37#include "popen.h" 37#include "popen.h"
38#include "utils.h" 38#include "utils.h"
39 39
40#include <signal.h>
41
40#define WARN_DUPLICATES "DUPLICATES FOUND! " 42#define WARN_DUPLICATES "DUPLICATES FOUND! "
41#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */ 43#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
42 44
@@ -138,7 +140,7 @@ main (int argc, char **argv)
138 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { 140 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) {
139 printf ("%s\n", cmd); 141 printf ("%s\n", cmd);
140 die (STATE_UNKNOWN, 142 die (STATE_UNKNOWN,
141 _("CRITICAL - Could not interpret output from ping command\n")); 143 _("CRITICAL - Could not interpret output from ping command\n"));
142 } 144 }
143 145
144 if (pl >= cpl || rta >= crta || rta < 0) 146 if (pl >= cpl || rta >= crta || rta < 0)
@@ -163,10 +165,14 @@ main (int argc, char **argv)
163 printf ("</A>"); 165 printf ("</A>");
164 166
165 /* Print performance data */ 167 /* Print performance data */
166 printf("|%s", fperfdata ("rta", (double) rta, "ms", 168 if (pl != 100) {
167 wrta>0?TRUE:FALSE, wrta, 169 printf("|%s", fperfdata ("rta", (double) rta, "ms",
168 crta>0?TRUE:FALSE, crta, 170 wrta>0?TRUE:FALSE, wrta,
169 TRUE, 0, FALSE, 0)); 171 crta>0?TRUE:FALSE, crta,
172 TRUE, 0, FALSE, 0));
173 } else {
174 printf("| rta=U;%f;%f;;", wrta, crta);
175 }
170 printf(" %s\n", perfdata ("pl", (long) pl, "%", 176 printf(" %s\n", perfdata ("pl", (long) pl, "%",
171 wpl>0?TRUE:FALSE, wpl, 177 wpl>0?TRUE:FALSE, wpl,
172 cpl>0?TRUE:FALSE, cpl, 178 cpl>0?TRUE:FALSE, cpl,
@@ -521,12 +527,13 @@ int
521error_scan (char buf[MAX_INPUT_BUFFER], const char *addr) 527error_scan (char buf[MAX_INPUT_BUFFER], const char *addr)
522{ 528{
523 if (strstr (buf, "Network is unreachable") || 529 if (strstr (buf, "Network is unreachable") ||
524 strstr (buf, "Destination Net Unreachable") 530 strstr (buf, "Destination Net Unreachable") ||
531 strstr (buf, "No route")
525 ) 532 )
526 die (STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr); 533 die (STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
527 else if (strstr (buf, "Destination Host Unreachable")) 534 else if (strstr (buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable"))
528 die (STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr); 535 die (STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
529 else if (strstr (buf, "Destination Port Unreachable")) 536 else if (strstr (buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable"))
530 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr); 537 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
531 else if (strstr (buf, "Destination Protocol Unreachable")) 538 else if (strstr (buf, "Destination Protocol Unreachable"))
532 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr); 539 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
@@ -534,11 +541,11 @@ error_scan (char buf[MAX_INPUT_BUFFER], const char *addr)
534 die (STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr); 541 die (STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
535 else if (strstr (buf, "Destination Host Prohibited")) 542 else if (strstr (buf, "Destination Host Prohibited"))
536 die (STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr); 543 die (STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
537 else if (strstr (buf, "Packet filtered")) 544 else if (strstr (buf, "Packet filtered") || strstr(buf, "Administratively prohibited"))
538 die (STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr); 545 die (STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
539 else if (strstr (buf, "unknown host" )) 546 else if (strstr (buf, "unknown host" ))
540 die (STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr); 547 die (STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
541 else if (strstr (buf, "Time to live exceeded")) 548 else if (strstr (buf, "Time to live exceeded") || strstr(buf, "Time exceeded"))
542 die (STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr); 549 die (STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
543 else if (strstr (buf, "Destination unreachable: ")) 550 else if (strstr (buf, "Destination unreachable: "))
544 die (STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr); 551 die (STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
@@ -547,7 +554,7 @@ error_scan (char buf[MAX_INPUT_BUFFER], const char *addr)
547 if (warn_text == NULL) 554 if (warn_text == NULL)
548 warn_text = strdup (_(WARN_DUPLICATES)); 555 warn_text = strdup (_(WARN_DUPLICATES));
549 else if (! strstr (warn_text, _(WARN_DUPLICATES)) && 556 else if (! strstr (warn_text, _(WARN_DUPLICATES)) &&
550 xasprintf (&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) 557 xasprintf (&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1)
551 die (STATE_UNKNOWN, _("Unable to realloc warn_text\n")); 558 die (STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
552 return (STATE_WARNING); 559 return (STATE_WARNING);
553 } 560 }
@@ -567,7 +574,7 @@ print_help (void)
567 574
568 printf (_("Use ping to check connection statistics for a remote host.")); 575 printf (_("Use ping to check connection statistics for a remote host."));
569 576
570 printf ("\n\n"); 577 printf ("\n\n");
571 578
572 print_usage (); 579 print_usage ();
573 580
@@ -577,29 +584,29 @@ print_help (void)
577 printf (UT_IPv46); 584 printf (UT_IPv46);
578 585
579 printf (" %s\n", "-H, --hostname=HOST"); 586 printf (" %s\n", "-H, --hostname=HOST");
580 printf (" %s\n", _("host to ping")); 587 printf (" %s\n", _("host to ping"));
581 printf (" %s\n", "-w, --warning=THRESHOLD"); 588 printf (" %s\n", "-w, --warning=THRESHOLD");
582 printf (" %s\n", _("warning threshold pair")); 589 printf (" %s\n", _("warning threshold pair"));
583 printf (" %s\n", "-c, --critical=THRESHOLD"); 590 printf (" %s\n", "-c, --critical=THRESHOLD");
584 printf (" %s\n", _("critical threshold pair")); 591 printf (" %s\n", _("critical threshold pair"));
585 printf (" %s\n", "-p, --packets=INTEGER"); 592 printf (" %s\n", "-p, --packets=INTEGER");
586 printf (" %s ", _("number of ICMP ECHO packets to send")); 593 printf (" %s ", _("number of ICMP ECHO packets to send"));
587 printf (_("(Default: %d)\n"), DEFAULT_MAX_PACKETS); 594 printf (_("(Default: %d)\n"), DEFAULT_MAX_PACKETS);
588 printf (" %s\n", "-L, --link"); 595 printf (" %s\n", "-L, --link");
589 printf (" %s\n", _("show HTML in the plugin output (obsoleted by urlize)")); 596 printf (" %s\n", _("show HTML in the plugin output (obsoleted by urlize)"));
590 597
591 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 598 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
592 599
593 printf ("\n"); 600 printf ("\n");
594 printf ("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel")); 601 printf ("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel"));
595 printf ("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the")); 602 printf ("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the"));
596 printf ("%s\n", _("percentage of packet loss to trigger an alarm state.")); 603 printf ("%s\n", _("percentage of packet loss to trigger an alarm state."));
597 604
598 printf ("\n"); 605 printf ("\n");
599 printf ("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); 606 printf ("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss"));
600 printf ("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); 607 printf ("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output"));
601 printf ("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in")); 608 printf ("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
602 printf ("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/")); 609 printf ("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
603 610
604 printf (UT_SUPPORT); 611 printf (UT_SUPPORT);
605} 612}
@@ -607,7 +614,7 @@ print_help (void)
607void 614void
608print_usage (void) 615print_usage (void)
609{ 616{
610 printf ("%s\n", _("Usage:")); 617 printf ("%s\n", _("Usage:"));
611 printf ("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname); 618 printf ("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
612 printf (" [-p packets] [-t timeout] [-4|-6]\n"); 619 printf (" [-p packets] [-t timeout] [-4|-6]\n");
613} 620}
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 4bcc56b..c17c699 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,34 +1,34 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_procs plugin 3* Monitoring check_procs plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6* Copyright (c) 2000-2008 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
10* This file contains the check_procs plugin 10* This file contains the check_procs plugin
11* 11*
12* Checks all processes and generates WARNING or CRITICAL states if the 12* Checks all processes and generates WARNING or CRITICAL states if the
13* specified metric is outside the required threshold ranges. The metric 13* specified metric is outside the required threshold ranges. The metric
14* defaults to number of processes. Search filters can be applied to limit 14* defaults to number of processes. Search filters can be applied to limit
15* the processes to check. 15* the processes to check.
16* 16*
17* 17*
18* This program is free software: you can redistribute it and/or modify 18* This program is free software: you can redistribute it and/or modify
19* it under the terms of the GNU General Public License as published by 19* it under the terms of the GNU General Public License as published by
20* the Free Software Foundation, either version 3 of the License, or 20* the Free Software Foundation, either version 3 of the License, or
21* (at your option) any later version. 21* (at your option) any later version.
22* 22*
23* This program is distributed in the hope that it will be useful, 23* This program is distributed in the hope that it will be useful,
24* but WITHOUT ANY WARRANTY; without even the implied warranty of 24* but WITHOUT ANY WARRANTY; without even the implied warranty of
25* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26* GNU General Public License for more details. 26* GNU General Public License for more details.
27* 27*
28* You should have received a copy of the GNU General Public License 28* You should have received a copy of the GNU General Public License
29* along with this program. If not, see <http://www.gnu.org/licenses/>. 29* along with this program. If not, see <http://www.gnu.org/licenses/>.
30* 30*
31* 31*
32*****************************************************************************/ 32*****************************************************************************/
33 33
34const char *progname = "check_procs"; 34const char *progname = "check_procs";
@@ -50,7 +50,7 @@ const char *email = "devel@monitoring-plugins.org";
50 50
51int process_arguments (int, char **); 51int process_arguments (int, char **);
52int validate_arguments (void); 52int validate_arguments (void);
53int convert_to_seconds (char *); 53int convert_to_seconds (char *);
54void print_help (void); 54void print_help (void);
55void print_usage (void); 55void print_usage (void);
56 56
@@ -70,6 +70,7 @@ int options = 0; /* bitmask of filter criteria to test against */
70#define PCPU 256 70#define PCPU 256
71#define ELAPSED 512 71#define ELAPSED 512
72#define EREG_ARGS 1024 72#define EREG_ARGS 1024
73#define EXCLUDE_PROGS 2048
73 74
74#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads: 75#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads:
75 ppid of procs are compared to pid of this proc*/ 76 ppid of procs are compared to pid of this proc*/
@@ -93,6 +94,9 @@ int rss;
93float pcpu; 94float pcpu;
94char *statopts; 95char *statopts;
95char *prog; 96char *prog;
97char *exclude_progs;
98char **exclude_progs_arr = NULL;
99char exclude_progs_counter = 0;
96char *args; 100char *args;
97char *input_filename = NULL; 101char *input_filename = NULL;
98regex_t re_args; 102regex_t re_args;
@@ -230,9 +234,9 @@ main (int argc, char **argv)
230 procseconds = convert_to_seconds(procetime); 234 procseconds = convert_to_seconds(procetime);
231 235
232 if (verbose >= 3) 236 if (verbose >= 3)
233 printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 237 printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n",
234 procs, procuid, procvsz, procrss, 238 procs, procuid, procvsz, procrss,
235 procpid, procppid, procpcpu, procstat, 239 procpid, procppid, procpcpu, procstat,
236 procetime, procprog, procargs); 240 procetime, procprog, procargs);
237 241
238 /* Ignore self */ 242 /* Ignore self */
@@ -250,7 +254,26 @@ main (int argc, char **argv)
250 continue; 254 continue;
251 } 255 }
252 256
253 /* filter kernel threads (childs of KTHREAD_PARENT)*/ 257 /* Ignore excluded processes by name */
258 if(options & EXCLUDE_PROGS) {
259 int found = 0;
260 int i = 0;
261
262 for(i=0; i < (exclude_progs_counter); i++) {
263 if(!strcmp(procprog, exclude_progs_arr[i])) {
264 found = 1;
265 }
266 }
267 if(found == 0) {
268 resultsum |= EXCLUDE_PROGS;
269 } else
270 {
271 if(verbose >= 3)
272 printf("excluding - by ignorelist\n");
273 }
274 }
275
276 /* filter kernel threads (children of KTHREAD_PARENT)*/
254 /* TODO adapt for other OSes than GNU/Linux 277 /* TODO adapt for other OSes than GNU/Linux
255 sorry for not doing that, but I've no other OSes to test :-( */ 278 sorry for not doing that, but I've no other OSes to test :-( */
256 if (kthread_filter == 1) { 279 if (kthread_filter == 1) {
@@ -265,7 +288,7 @@ main (int argc, char **argv)
265 } 288 }
266 } 289 }
267 290
268 if ((options & STAT) && (strstr (statopts, procstat))) 291 if ((options & STAT) && (strstr (procstat, statopts)))
269 resultsum |= STAT; 292 resultsum |= STAT;
270 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 293 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
271 resultsum |= ARGS; 294 resultsum |= ARGS;
@@ -292,9 +315,9 @@ main (int argc, char **argv)
292 315
293 procs++; 316 procs++;
294 if (verbose >= 2) { 317 if (verbose >= 2) {
295 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 318 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n",
296 procuid, procvsz, procrss, 319 procuid, procvsz, procrss,
297 procpid, procppid, procpcpu, procstat, 320 procpid, procppid, procpcpu, procstat,
298 procetime, procprog, procargs); 321 procetime, procprog, procargs);
299 } 322 }
300 323
@@ -320,7 +343,7 @@ main (int argc, char **argv)
320 result = max_state (result, i); 343 result = max_state (result, i);
321 } 344 }
322 } 345 }
323 } 346 }
324 /* This should not happen */ 347 /* This should not happen */
325 else if (verbose) { 348 else if (verbose) {
326 printf(_("Not parseable: %s"), input_buffer); 349 printf(_("Not parseable: %s"), input_buffer);
@@ -332,7 +355,7 @@ main (int argc, char **argv)
332 return STATE_UNKNOWN; 355 return STATE_UNKNOWN;
333 } 356 }
334 357
335 if ( result == STATE_UNKNOWN ) 358 if ( result == STATE_UNKNOWN )
336 result = STATE_OK; 359 result = STATE_OK;
337 360
338 /* Needed if procs found, but none match filter */ 361 /* Needed if procs found, but none match filter */
@@ -352,9 +375,9 @@ main (int argc, char **argv)
352 if (metric != METRIC_PROCS) { 375 if (metric != METRIC_PROCS) {
353 printf (_("%d crit, %d warn out of "), crit, warn); 376 printf (_("%d crit, %d warn out of "), crit, warn);
354 } 377 }
355 } 378 }
356 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 379 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs);
357 380
358 if (strcmp(fmt,"") != 0) { 381 if (strcmp(fmt,"") != 0) {
359 printf (_(" with %s"), fmt); 382 printf (_(" with %s"), fmt);
360 } 383 }
@@ -409,6 +432,7 @@ process_arguments (int argc, char **argv)
409 {"input-file", required_argument, 0, CHAR_MAX+2}, 432 {"input-file", required_argument, 0, CHAR_MAX+2},
410 {"no-kthreads", required_argument, 0, 'k'}, 433 {"no-kthreads", required_argument, 0, 'k'},
411 {"traditional-filter", no_argument, 0, 'T'}, 434 {"traditional-filter", no_argument, 0, 'T'},
435 {"exclude-process", required_argument, 0, 'X'},
412 {0, 0, 0, 0} 436 {0, 0, 0, 0}
413 }; 437 };
414 438
@@ -417,7 +441,7 @@ process_arguments (int argc, char **argv)
417 strcpy (argv[c], "-t"); 441 strcpy (argv[c], "-t");
418 442
419 while (1) { 443 while (1) {
420 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T", 444 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:",
421 longopts, &option); 445 longopts, &option);
422 446
423 if (c == -1 || c == EOF) 447 if (c == -1 || c == EOF)
@@ -440,7 +464,7 @@ process_arguments (int argc, char **argv)
440 break; 464 break;
441 case 'c': /* critical threshold */ 465 case 'c': /* critical threshold */
442 critical_range = optarg; 466 critical_range = optarg;
443 break; 467 break;
444 case 'w': /* warning threshold */ 468 case 'w': /* warning threshold */
445 warning_range = optarg; 469 warning_range = optarg;
446 break; 470 break;
@@ -490,6 +514,23 @@ process_arguments (int argc, char **argv)
490 prog); 514 prog);
491 options |= PROG; 515 options |= PROG;
492 break; 516 break;
517 case 'X':
518 if(exclude_progs)
519 break;
520 else
521 exclude_progs = optarg;
522 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
523 exclude_progs);
524 char *p = strtok(exclude_progs, ",");
525
526 while(p){
527 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter);
528 exclude_progs_arr[exclude_progs_counter-1] = p;
529 p = strtok(NULL, ",");
530 }
531
532 options |= EXCLUDE_PROGS;
533 break;
493 case 'a': /* args (full path name with args) */ 534 case 'a': /* args (full path name with args) */
494 /* TODO: allow this to be passed in with --metric */ 535 /* TODO: allow this to be passed in with --metric */
495 if (args) 536 if (args)
@@ -542,11 +583,11 @@ process_arguments (int argc, char **argv)
542 if ( strcmp(optarg, "PROCS") == 0) { 583 if ( strcmp(optarg, "PROCS") == 0) {
543 metric = METRIC_PROCS; 584 metric = METRIC_PROCS;
544 break; 585 break;
545 } 586 }
546 else if ( strcmp(optarg, "VSZ") == 0) { 587 else if ( strcmp(optarg, "VSZ") == 0) {
547 metric = METRIC_VSZ; 588 metric = METRIC_VSZ;
548 break; 589 break;
549 } 590 }
550 else if ( strcmp(optarg, "RSS") == 0 ) { 591 else if ( strcmp(optarg, "RSS") == 0 ) {
551 metric = METRIC_RSS; 592 metric = METRIC_RSS;
552 break; 593 break;
@@ -559,7 +600,7 @@ process_arguments (int argc, char **argv)
559 metric = METRIC_ELAPSED; 600 metric = METRIC_ELAPSED;
560 break; 601 break;
561 } 602 }
562 603
563 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 604 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
564 case 'k': /* linux kernel thread filter */ 605 case 'k': /* linux kernel thread filter */
565 kthread_filter = 1; 606 kthread_filter = 1;
@@ -642,7 +683,7 @@ convert_to_seconds(char *etime) {
642 seconds = 0; 683 seconds = 0;
643 684
644 for (ptr = etime; *ptr != '\0'; ptr++) { 685 for (ptr = etime; *ptr != '\0'; ptr++) {
645 686
646 if (*ptr == '-') { 687 if (*ptr == '-') {
647 hyphcnt++; 688 hyphcnt++;
648 continue; 689 continue;
@@ -745,6 +786,8 @@ print_help (void)
745 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 786 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING."));
746 printf (" %s\n", "-C, --command=COMMAND"); 787 printf (" %s\n", "-C, --command=COMMAND");
747 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 788 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
789 printf (" %s\n", "-X, --exclude-process");
790 printf (" %s\n", _("Exclude processes which match this comma separated list"));
748 printf (" %s\n", "-k, --no-kthreads"); 791 printf (" %s\n", "-k, --no-kthreads");
749 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 792 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
750 793
@@ -764,13 +807,18 @@ be the total number of running processes\n\n"));
764 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 807 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
765 printf (" %s\n", _("Warning if not two processes with command name portsentry.")); 808 printf (" %s\n", _("Warning if not two processes with command name portsentry."));
766 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 809 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes"));
810 printf (" %s\n", "check_procs -c 1: -C sshd");
811 printf (" %s\n", _("Critical if not at least 1 process with command sshd"));
812 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd");
813 printf (" %s\n", _("Warning if > 1024 processes with command name sshd."));
814 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd."));
767 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root"); 815 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
768 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing")); 816 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
769 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root")); 817 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
770 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 818 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
771 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K")); 819 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
772 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU"); 820 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
773 printf (" %s\n", _("Alert if CPU of any processes over 10%% or 20%%")); 821 printf (" %s\n", _("Alert if CPU of any processes over 10\% or 20\%"));
774 822
775 printf (UT_SUPPORT); 823 printf (UT_SUPPORT);
776} 824}
@@ -781,5 +829,5 @@ print_usage (void)
781 printf ("%s\n", _("Usage:")); 829 printf ("%s\n", _("Usage:"));
782 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); 830 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
783 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n"); 831 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
784 printf (" [-C command] [-k] [-t timeout] [-v]\n"); 832 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
785} 833}
diff --git a/plugins/check_radius.c b/plugins/check_radius.c
index be1001b..b1b4938 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -97,7 +97,7 @@ int verbose = FALSE;
97 97
98/****************************************************************************** 98/******************************************************************************
99 99
100The (psuedo?)literate programming XML is contained within \@\@\- <XML> \-\@\@ 100The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
101tags in the comments. With in the tags, the XML is assembled sequentially. 101tags in the comments. With in the tags, the XML is assembled sequentially.
102You can define entities in tags. You also have all the #defines available as 102You can define entities in tags. You also have all the #defines available as
103entities. 103entities.
@@ -155,7 +155,11 @@ main (int argc, char **argv)
155{ 155{
156 struct sockaddr_storage ss; 156 struct sockaddr_storage ss;
157 char name[HOST_NAME_MAX]; 157 char name[HOST_NAME_MAX];
158#ifdef RC_BUFFER_LEN
159 char msg[RC_BUFFER_LEN];
160#else
158 char msg[BUFFER_LEN]; 161 char msg[BUFFER_LEN];
162#endif
159 SEND_DATA data; 163 SEND_DATA data;
160 int result = STATE_UNKNOWN; 164 int result = STATE_UNKNOWN;
161 uint32_t client_id, service; 165 uint32_t client_id, service;
@@ -377,7 +381,7 @@ print_help (void)
377 printf ("\n"); 381 printf ("\n");
378 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections.")); 382 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
379 printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user")); 383 printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
380 printf ("%s\n", _("name and password. A configuration file may also be present. The format of")); 384 printf ("%s\n", _("name and password. A configuration file must be present. The format of"));
381 printf ("%s\n", _("the configuration file is described in the radiusclient library sources.")); 385 printf ("%s\n", _("the configuration file is described in the radiusclient library sources."));
382 printf ("%s\n", _("The password option presents a substantial security issue because the")); 386 printf ("%s\n", _("The password option presents a substantial security issue because the"));
383 printf ("%s\n", _("password can possibly be determined by careful watching of the command line")); 387 printf ("%s\n", _("password can possibly be determined by careful watching of the command line"));
diff --git a/plugins/check_real.c b/plugins/check_real.c
index 0f1a1ba..fbdb70f 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -178,7 +178,7 @@ main (int argc, char **argv)
178 178
179 /* watch for the REAL connection string */ 179 /* watch for the REAL connection string */
180 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 180 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
181 buffer[result] = '\0'; /* null terminate recieved buffer */ 181 buffer[result] = '\0'; /* null terminate received buffer */
182 182
183 /* return a CRITICAL status if we couldn't read any data */ 183 /* return a CRITICAL status if we couldn't read any data */
184 if (result == -1) { 184 if (result == -1) {
@@ -436,7 +436,7 @@ print_help (void)
436 436
437 printf ("\n"); 437 printf ("\n");
438 printf ("%s\n", _("This plugin will attempt to open an RTSP connection with the host.")); 438 printf ("%s\n", _("This plugin will attempt to open an RTSP connection with the host."));
439 printf ("%s\n", _("Successul connects return STATE_OK, refusals and timeouts return")); 439 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
440 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,")); 440 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,"));
441 printf ("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return")); 441 printf ("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return"));
442 printf ("%s\n", _("values.")); 442 printf ("%s\n", _("values."));
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index 0fcf4c6..fc0ae2c 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -3,7 +3,7 @@
3* Monitoring check_smtp plugin 3* Monitoring check_smtp plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6* Copyright (c) 2000-2023 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
@@ -42,19 +42,22 @@ const char *email = "devel@monitoring-plugins.org";
42#ifdef HAVE_SSL 42#ifdef HAVE_SSL
43int check_cert = FALSE; 43int check_cert = FALSE;
44int days_till_exp_warn, days_till_exp_crit; 44int days_till_exp_warn, days_till_exp_crit;
45# define my_recv(buf, len) ((use_ssl && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 45# define my_recv(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
46# define my_send(buf, len) ((use_ssl && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0)) 46# define my_send(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
47#else /* ifndef HAVE_SSL */ 47#else /* ifndef HAVE_SSL */
48# define my_recv(buf, len) read(sd, buf, len) 48# define my_recv(buf, len) read(sd, buf, len)
49# define my_send(buf, len) send(sd, buf, len, 0) 49# define my_send(buf, len) send(sd, buf, len, 0)
50#endif 50#endif
51 51
52enum { 52enum {
53 SMTP_PORT = 25 53 SMTP_PORT = 25,
54 SMTPS_PORT = 465
54}; 55};
56#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
55#define SMTP_EXPECT "220" 57#define SMTP_EXPECT "220"
56#define SMTP_HELO "HELO " 58#define SMTP_HELO "HELO "
57#define SMTP_EHLO "EHLO " 59#define SMTP_EHLO "EHLO "
60#define SMTP_LHLO "LHLO "
58#define SMTP_QUIT "QUIT\r\n" 61#define SMTP_QUIT "QUIT\r\n"
59#define SMTP_STARTTLS "STARTTLS\r\n" 62#define SMTP_STARTTLS "STARTTLS\r\n"
60#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n" 63#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
@@ -81,6 +84,7 @@ int eflags = 0;
81int errcode, excode; 84int errcode, excode;
82 85
83int server_port = SMTP_PORT; 86int server_port = SMTP_PORT;
87int server_port_option = 0;
84char *server_address = NULL; 88char *server_address = NULL;
85char *server_expect = NULL; 89char *server_expect = NULL;
86char *mail_command = NULL; 90char *mail_command = NULL;
@@ -101,7 +105,11 @@ double critical_time = 0;
101int check_critical_time = FALSE; 105int check_critical_time = FALSE;
102int verbose = 0; 106int verbose = 0;
103int use_ssl = FALSE; 107int use_ssl = FALSE;
108int use_starttls = FALSE;
109int use_sni = FALSE;
110short use_proxy_prefix = FALSE;
104short use_ehlo = FALSE; 111short use_ehlo = FALSE;
112short use_lhlo = FALSE;
105short ssl_established = 0; 113short ssl_established = 0;
106char *localhostname = NULL; 114char *localhostname = NULL;
107int sd; 115int sd;
@@ -152,7 +160,9 @@ main (int argc, char **argv)
152 return STATE_CRITICAL; 160 return STATE_CRITICAL;
153 } 161 }
154 } 162 }
155 if(use_ehlo) 163 if(use_lhlo)
164 xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
165 else if(use_ehlo)
156 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n"); 166 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
157 else 167 else
158 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n"); 168 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
@@ -179,6 +189,26 @@ main (int argc, char **argv)
179 result = my_tcp_connect (server_address, server_port, &sd); 189 result = my_tcp_connect (server_address, server_port, &sd);
180 190
181 if (result == STATE_OK) { /* we connected */ 191 if (result == STATE_OK) { /* we connected */
192 /* If requested, send PROXY header */
193 if (use_proxy_prefix) {
194 if (verbose)
195 printf ("Sending header %s\n", PROXY_PREFIX);
196 my_send(PROXY_PREFIX, strlen(PROXY_PREFIX));
197 }
198
199#ifdef HAVE_SSL
200 if (use_ssl) {
201 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL));
202 if (result != STATE_OK) {
203 printf (_("CRITICAL - Cannot create SSL context.\n"));
204 close(sd);
205 np_net_ssl_cleanup();
206 return STATE_CRITICAL;
207 } else {
208 ssl_established = 1;
209 }
210 }
211#endif
182 212
183 /* watch for the SMTP connection string and */ 213 /* watch for the SMTP connection string and */
184 /* return a WARNING status if we couldn't read any data */ 214 /* return a WARNING status if we couldn't read any data */
@@ -191,27 +221,27 @@ main (int argc, char **argv)
191 xasprintf(&server_response, "%s", buffer); 221 xasprintf(&server_response, "%s", buffer);
192 222
193 /* send the HELO/EHLO command */ 223 /* send the HELO/EHLO command */
194 send(sd, helocmd, strlen(helocmd), 0); 224 my_send(helocmd, strlen(helocmd));
195 225
196 /* allow for response to helo command to reach us */ 226 /* allow for response to helo command to reach us */
197 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 227 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
198 printf (_("recv() failed\n")); 228 printf (_("recv() failed\n"));
199 return STATE_WARNING; 229 return STATE_WARNING;
200 } else if(use_ehlo){ 230 } else if(use_ehlo || use_lhlo){
201 if(strstr(buffer, "250 STARTTLS") != NULL || 231 if(strstr(buffer, "250 STARTTLS") != NULL ||
202 strstr(buffer, "250-STARTTLS") != NULL){ 232 strstr(buffer, "250-STARTTLS") != NULL){
203 supports_tls=TRUE; 233 supports_tls=TRUE;
204 } 234 }
205 } 235 }
206 236
207 if(use_ssl && ! supports_tls){ 237 if(use_starttls && ! supports_tls){
208 printf(_("WARNING - TLS not supported by server\n")); 238 printf(_("WARNING - TLS not supported by server\n"));
209 smtp_quit(); 239 smtp_quit();
210 return STATE_WARNING; 240 return STATE_WARNING;
211 } 241 }
212 242
213#ifdef HAVE_SSL 243#ifdef HAVE_SSL
214 if(use_ssl) { 244 if(use_starttls) {
215 /* send the STARTTLS command */ 245 /* send the STARTTLS command */
216 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 246 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
217 247
@@ -221,7 +251,7 @@ main (int argc, char **argv)
221 smtp_quit(); 251 smtp_quit();
222 return STATE_UNKNOWN; 252 return STATE_UNKNOWN;
223 } 253 }
224 result = np_net_ssl_init(sd); 254 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL));
225 if(result != STATE_OK) { 255 if(result != STATE_OK) {
226 printf (_("CRITICAL - Cannot create SSL context.\n")); 256 printf (_("CRITICAL - Cannot create SSL context.\n"));
227 close(sd); 257 close(sd);
@@ -293,6 +323,7 @@ main (int argc, char **argv)
293 printf("%s", buffer); 323 printf("%s", buffer);
294 } 324 }
295 325
326 n = 0;
296 while (n < ncommands) { 327 while (n < ncommands) {
297 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 328 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n");
298 my_send(cmd_str, strlen(cmd_str)); 329 my_send(cmd_str, strlen(cmd_str));
@@ -449,6 +480,10 @@ process_arguments (int argc, char **argv)
449 int c; 480 int c;
450 char* temp; 481 char* temp;
451 482
483 enum {
484 SNI_OPTION
485 };
486
452 int option = 0; 487 int option = 0;
453 static struct option longopts[] = { 488 static struct option longopts[] = {
454 {"hostname", required_argument, 0, 'H'}, 489 {"hostname", required_argument, 0, 'H'},
@@ -469,9 +504,14 @@ process_arguments (int argc, char **argv)
469 {"use-ipv4", no_argument, 0, '4'}, 504 {"use-ipv4", no_argument, 0, '4'},
470 {"use-ipv6", no_argument, 0, '6'}, 505 {"use-ipv6", no_argument, 0, '6'},
471 {"help", no_argument, 0, 'h'}, 506 {"help", no_argument, 0, 'h'},
507 {"lmtp", no_argument, 0, 'L'},
508 {"ssl", no_argument, 0, 's'},
509 {"tls", no_argument, 0, 's'},
472 {"starttls",no_argument,0,'S'}, 510 {"starttls",no_argument,0,'S'},
511 {"sni", no_argument, 0, SNI_OPTION},
473 {"certificate",required_argument,0,'D'}, 512 {"certificate",required_argument,0,'D'},
474 {"ignore-quit-failure",no_argument,0,'q'}, 513 {"ignore-quit-failure",no_argument,0,'q'},
514 {"proxy",no_argument,0,'r'},
475 {0, 0, 0, 0} 515 {0, 0, 0, 0}
476 }; 516 };
477 517
@@ -488,7 +528,7 @@ process_arguments (int argc, char **argv)
488 } 528 }
489 529
490 while (1) { 530 while (1) {
491 c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:F:A:U:P:q", 531 c = getopt_long (argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q",
492 longopts, &option); 532 longopts, &option);
493 533
494 if (c == -1 || c == EOF) 534 if (c == -1 || c == EOF)
@@ -505,7 +545,7 @@ process_arguments (int argc, char **argv)
505 break; 545 break;
506 case 'p': /* port */ 546 case 'p': /* port */
507 if (is_intpos (optarg)) 547 if (is_intpos (optarg))
508 server_port = atoi (optarg); 548 server_port_option = atoi (optarg);
509 else 549 else
510 usage4 (_("Port must be a positive integer")); 550 usage4 (_("Port must be a positive integer"));
511 break; 551 break;
@@ -610,11 +650,29 @@ process_arguments (int argc, char **argv)
610#else 650#else
611 usage (_("SSL support not available - install OpenSSL and recompile")); 651 usage (_("SSL support not available - install OpenSSL and recompile"));
612#endif 652#endif
653 case 's':
654 /* ssl */
655 use_ssl = TRUE;
656 server_port = SMTPS_PORT;
657 break;
613 case 'S': 658 case 'S':
614 /* starttls */ 659 /* starttls */
615 use_ssl = TRUE; 660 use_starttls = TRUE;
616 use_ehlo = TRUE; 661 use_ehlo = TRUE;
617 break; 662 break;
663 case SNI_OPTION:
664#ifdef HAVE_SSL
665 use_sni = TRUE;
666#else
667 usage (_("SSL support not available - install OpenSSL and recompile"));
668#endif
669 break;
670 case 'r':
671 use_proxy_prefix = TRUE;
672 break;
673 case 'L':
674 use_lhlo = TRUE;
675 break;
618 case '4': 676 case '4':
619 address_family = AF_INET; 677 address_family = AF_INET;
620 break; 678 break;
@@ -658,6 +716,14 @@ process_arguments (int argc, char **argv)
658 if (from_arg==NULL) 716 if (from_arg==NULL)
659 from_arg = strdup(" "); 717 from_arg = strdup(" ");
660 718
719 if (use_starttls && use_ssl) {
720 usage4 (_("Set either -s/--ssl/--tls or -S/--starttls"));
721 }
722
723 if (server_port_option != 0) {
724 server_port = server_port_option;
725 }
726
661 return validate_arguments (); 727 return validate_arguments ();
662} 728}
663 729
@@ -810,11 +876,18 @@ print_help (void)
810 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), 876 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")),
811 printf (" %s\n", "-F, --fqdn=STRING"); 877 printf (" %s\n", "-F, --fqdn=STRING");
812 printf (" %s\n", _("FQDN used for HELO")); 878 printf (" %s\n", _("FQDN used for HELO"));
879 printf (" %s\n", "-r, --proxy");
880 printf (" %s\n", _("Use PROXY protocol prefix for the connection."));
813#ifdef HAVE_SSL 881#ifdef HAVE_SSL
814 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 882 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
815 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 883 printf (" %s\n", _("Minimum number of days a certificate has to be valid."));
884 printf (" %s\n", "-s, --ssl, --tls");
885 printf (" %s\n", _("Use SSL/TLS for the connection."));
886 printf (_(" Sets default port to %d.\n"), SMTPS_PORT);
816 printf (" %s\n", "-S, --starttls"); 887 printf (" %s\n", "-S, --starttls");
817 printf (" %s\n", _("Use STARTTLS for the connection.")); 888 printf (" %s\n", _("Use STARTTLS for the connection."));
889 printf (" %s\n", "--sni");
890 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
818#endif 891#endif
819 892
820 printf (" %s\n", "-A, --authtype=STRING"); 893 printf (" %s\n", "-A, --authtype=STRING");
@@ -823,6 +896,8 @@ print_help (void)
823 printf (" %s\n", _("SMTP AUTH username")); 896 printf (" %s\n", _("SMTP AUTH username"));
824 printf (" %s\n", "-P, --authpass=STRING"); 897 printf (" %s\n", "-P, --authpass=STRING");
825 printf (" %s\n", _("SMTP AUTH password")); 898 printf (" %s\n", _("SMTP AUTH password"));
899 printf (" %s\n", "-L, --lmtp");
900 printf (" %s\n", _("Send LHLO instead of HELO/EHLO"));
826 printf (" %s\n", "-q, --ignore-quit-failure"); 901 printf (" %s\n", "-q, --ignore-quit-failure");
827 printf (" %s\n", _("Ignore failure when sending QUIT command to server")); 902 printf (" %s\n", _("Ignore failure when sending QUIT command to server"));
828 903
@@ -833,7 +908,7 @@ print_help (void)
833 printf (UT_VERBOSE); 908 printf (UT_VERBOSE);
834 909
835 printf("\n"); 910 printf("\n");
836 printf ("%s\n", _("Successul connects return STATE_OK, refusals and timeouts return")); 911 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
837 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful")); 912 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful"));
838 printf ("%s\n", _("connects, but incorrect response messages from the host result in")); 913 printf ("%s\n", _("connects, but incorrect response messages from the host result in"));
839 printf ("%s\n", _("STATE_WARNING return values.")); 914 printf ("%s\n", _("STATE_WARNING return values."));
@@ -849,6 +924,6 @@ print_usage (void)
849 printf ("%s\n", _("Usage:")); 924 printf ("%s\n", _("Usage:"));
850 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname); 925 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
851 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n"); 926 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
852 printf ("[-F fqdn] [-S] [-D warn days cert expire[,crit days cert expire]] [-v] \n"); 927 printf ("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
853} 928}
854 929
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c
index da9638c..56a586a 100644
--- a/plugins/check_snmp.c
+++ b/plugins/check_snmp.c
@@ -1,31 +1,31 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_snmp plugin 3* Monitoring check_snmp plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6* Copyright (c) 1999-2007 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
10* This file contains the check_snmp plugin 10* This file contains the check_snmp plugin
11* 11*
12* Check status of remote machines and obtain system information via SNMP 12* Check status of remote machines and obtain system information via SNMP
13* 13*
14* 14*
15* This program is free software: you can redistribute it and/or modify 15* This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16* it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17* the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18* (at your option) any later version.
19* 19*
20* This program is distributed in the hope that it will be useful, 20* This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21* but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23* GNU General Public License for more details.
24* 24*
25* You should have received a copy of the GNU General Public License 25* You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26* along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27*
28* 28*
29*****************************************************************************/ 29*****************************************************************************/
30 30
31const char *progname = "check_snmp"; 31const char *progname = "check_snmp";
@@ -46,6 +46,7 @@ const char *email = "devel@monitoring-plugins.org";
46#define DEFAULT_PRIV_PROTOCOL "DES" 46#define DEFAULT_PRIV_PROTOCOL "DES"
47#define DEFAULT_DELIMITER "=" 47#define DEFAULT_DELIMITER "="
48#define DEFAULT_OUTPUT_DELIMITER " " 48#define DEFAULT_OUTPUT_DELIMITER " "
49#define DEFAULT_BUFFER_SIZE 100
49 50
50#define mark(a) ((a)!=0?"*":"") 51#define mark(a) ((a)!=0?"*":"")
51 52
@@ -64,6 +65,7 @@ const char *email = "devel@monitoring-plugins.org";
64#define L_RATE_MULTIPLIER CHAR_MAX+2 65#define L_RATE_MULTIPLIER CHAR_MAX+2
65#define L_INVERT_SEARCH CHAR_MAX+3 66#define L_INVERT_SEARCH CHAR_MAX+3
66#define L_OFFSET CHAR_MAX+4 67#define L_OFFSET CHAR_MAX+4
68#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX+5
67 69
68/* Gobble to string - stop incrementing c when c[0] match one of the 70/* Gobble to string - stop incrementing c when c[0] match one of the
69 * characters in s */ 71 * characters in s */
@@ -90,6 +92,7 @@ char *thisarg (char *str);
90char *nextarg (char *str); 92char *nextarg (char *str);
91void print_usage (void); 93void print_usage (void);
92void print_help (void); 94void print_help (void);
95char *multiply (char *str);
93 96
94#include "regex.h" 97#include "regex.h"
95char regex_expect[MAX_INPUT_BUFFER] = ""; 98char regex_expect[MAX_INPUT_BUFFER] = "";
@@ -113,6 +116,7 @@ char *authproto = NULL;
113char *privproto = NULL; 116char *privproto = NULL;
114char *authpasswd = NULL; 117char *authpasswd = NULL;
115char *privpasswd = NULL; 118char *privpasswd = NULL;
119int nulloid = STATE_UNKNOWN;
116char **oids = NULL; 120char **oids = NULL;
117size_t oids_size = 0; 121size_t oids_size = 0;
118char *label; 122char *label;
@@ -153,6 +157,11 @@ double *previous_value;
153size_t previous_size = OID_COUNT_STEP; 157size_t previous_size = OID_COUNT_STEP;
154int perf_labels = 1; 158int perf_labels = 1;
155char* ip_version = ""; 159char* ip_version = "";
160double multiplier = 1.0;
161char *fmtstr = "";
162bool fmtstr_set = false;
163char buffer[DEFAULT_BUFFER_SIZE];
164bool ignore_mib_parsing_errors = false;
156 165
157static char *fix_snmp_range(char *th) 166static char *fix_snmp_range(char *th)
158{ 167{
@@ -300,42 +309,55 @@ main (int argc, char **argv)
300 } 309 }
301 310
302 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ 311 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */
303 command_line = calloc (10 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *)); 312
304 command_line[0] = snmpcmd; 313 unsigned index = 0;
305 command_line[1] = strdup ("-Le"); 314 command_line = calloc (11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *));
306 command_line[2] = strdup ("-t"); 315
307 xasprintf (&command_line[3], "%d", timeout_interval); 316 command_line[index++] = snmpcmd;
308 command_line[4] = strdup ("-r"); 317 command_line[index++] = strdup ("-Le");
309 xasprintf (&command_line[5], "%d", retries); 318 command_line[index++] = strdup ("-t");
310 command_line[6] = strdup ("-m"); 319 xasprintf (&command_line[index++], "%d", timeout_interval);
311 command_line[7] = strdup (miblist); 320 command_line[index++] = strdup ("-r");
312 command_line[8] = "-v"; 321 xasprintf (&command_line[index++], "%d", retries);
313 command_line[9] = strdup (proto); 322 command_line[index++] = strdup ("-m");
323 command_line[index++] = strdup (miblist);
324 command_line[index++] = "-v";
325 command_line[index++] = strdup (proto);
326
327 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s",
328 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto);
329
330 if (ignore_mib_parsing_errors) {
331 command_line[index++] = "-Pe";
332 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth);
333 }
334
314 335
315 for (i = 0; i < numcontext; i++) { 336 for (i = 0; i < numcontext; i++) {
316 command_line[10 + i] = contextargs[i]; 337 command_line[index++] = contextargs[i];
317 } 338 }
318 339
319 for (i = 0; i < numauthpriv; i++) { 340 for (i = 0; i < numauthpriv; i++) {
320 command_line[10 + numcontext + i] = authpriv[i]; 341 command_line[index++] = authpriv[i];
321 } 342 }
322 343
323 xasprintf (&command_line[10 + numcontext + numauthpriv], "%s:%s", server_address, port); 344 xasprintf (&command_line[index++], "%s:%s", server_address, port);
324 345
325 /* This is just for display purposes, so it can remain a string */ 346 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s",
326 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s %s %s %s:%s", 347 cl_hidden_auth,
327 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto, "[context]", "[authpriv]", 348 server_address,
328 server_address, port); 349 port);
329 350
330 for (i = 0; i < numoids; i++) { 351 for (i = 0; i < numoids; i++) {
331 command_line[10 + numcontext + numauthpriv + 1 + i] = oids[i]; 352 command_line[index++] = oids[i];
332 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]); 353 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
333 } 354 }
334 355
335 command_line[10 + numcontext + numauthpriv + 1 + numoids] = NULL; 356 command_line[index++] = NULL;
336 357
337 if (verbose) 358 if (verbose) {
338 printf ("%s\n", cl_hidden_auth); 359 printf ("%s\n", cl_hidden_auth);
360 }
339 361
340 /* Set signal handling and alarm */ 362 /* Set signal handling and alarm */
341 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { 363 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
@@ -375,7 +397,7 @@ main (int argc, char **argv)
375 } 397 }
376 } 398 }
377 399
378 for (line=0, i=0; line < chld_out.lines; line++, i++) { 400 for (line=0, i=0; line < chld_out.lines && i < numoids ; line++, i++) {
379 if(calculate_rate) 401 if(calculate_rate)
380 conv = "%.10g"; 402 conv = "%.10g";
381 else 403 else
@@ -397,15 +419,15 @@ main (int argc, char **argv)
397 is_counter=0; 419 is_counter=0;
398 /* We strip out the datatype indicator for PHBs */ 420 /* We strip out the datatype indicator for PHBs */
399 if (strstr (response, "Gauge: ")) { 421 if (strstr (response, "Gauge: ")) {
400 show = strstr (response, "Gauge: ") + 7; 422 show = multiply (strstr (response, "Gauge: ") + 7);
401 } 423 }
402 else if (strstr (response, "Gauge32: ")) { 424 else if (strstr (response, "Gauge32: ")) {
403 show = strstr (response, "Gauge32: ") + 9; 425 show = multiply (strstr (response, "Gauge32: ") + 9);
404 } 426 }
405 else if (strstr (response, "Counter32: ")) { 427 else if (strstr (response, "Counter32: ")) {
406 show = strstr (response, "Counter32: ") + 11; 428 show = strstr (response, "Counter32: ") + 11;
407 is_counter=1; 429 is_counter=1;
408 if(!calculate_rate) 430 if(!calculate_rate)
409 strcpy(type, "c"); 431 strcpy(type, "c");
410 } 432 }
411 else if (strstr (response, "Counter64: ")) { 433 else if (strstr (response, "Counter64: ")) {
@@ -415,7 +437,11 @@ main (int argc, char **argv)
415 strcpy(type, "c"); 437 strcpy(type, "c");
416 } 438 }
417 else if (strstr (response, "INTEGER: ")) { 439 else if (strstr (response, "INTEGER: ")) {
418 show = strstr (response, "INTEGER: ") + 9; 440 show = multiply (strstr (response, "INTEGER: ") + 9);
441
442 if (fmtstr_set) {
443 conv = fmtstr;
444 }
419 } 445 }
420 else if (strstr (response, "OID: ")) { 446 else if (strstr (response, "OID: ")) {
421 show = strstr (response, "OID: ") + 5; 447 show = strstr (response, "OID: ") + 5;
@@ -468,9 +494,20 @@ main (int argc, char **argv)
468 /* Process this block for numeric comparisons */ 494 /* Process this block for numeric comparisons */
469 /* Make some special values,like Timeticks numeric only if a threshold is defined */ 495 /* Make some special values,like Timeticks numeric only if a threshold is defined */
470 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) { 496 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) {
497 if (verbose > 2) {
498 print_thresholds(" thresholds", thlds[i]);
499 }
471 ptr = strpbrk (show, "-0123456789"); 500 ptr = strpbrk (show, "-0123456789");
472 if (ptr == NULL) 501 if (ptr == NULL){
473 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show); 502 if (nulloid == 3)
503 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show);
504 else if (nulloid == 0)
505 die (STATE_OK,_("No valid data returned (%s)\n"), show);
506 else if (nulloid == 1)
507 die (STATE_WARNING,_("No valid data returned (%s)\n"), show);
508 else if (nulloid == 2)
509 die (STATE_CRITICAL,_("No valid data returned (%s)\n"), show);
510 }
474 while (i >= response_size) { 511 while (i >= response_size) {
475 response_size += OID_COUNT_STEP; 512 response_size += OID_COUNT_STEP;
476 response_value = realloc(response_value, response_size * sizeof(*response_value)); 513 response_value = realloc(response_value, response_size * sizeof(*response_value));
@@ -576,20 +613,24 @@ main (int argc, char **argv)
576 len = sizeof(perfstr)-strlen(perfstr)-1; 613 len = sizeof(perfstr)-strlen(perfstr)-1;
577 strncat(perfstr, show, len>ptr-show ? ptr-show : len); 614 strncat(perfstr, show, len>ptr-show ? ptr-show : len);
578 615
616 if (strcmp(type, "") != 0) {
617 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
618 }
619
579 if (warning_thresholds) { 620 if (warning_thresholds) {
580 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 621 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
581 strncat(perfstr, warning_thresholds, sizeof(perfstr)-strlen(perfstr)-1); 622 if(thlds[i]->warning && thlds[i]->warning->text)
623 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr)-strlen(perfstr)-1);
582 } 624 }
583 625
584 if (critical_thresholds) { 626 if (critical_thresholds) {
585 if (!warning_thresholds) 627 if (!warning_thresholds)
586 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 628 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
587 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 629 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
588 strncat(perfstr, critical_thresholds, sizeof(perfstr)-strlen(perfstr)-1); 630 if(thlds[i]->critical && thlds[i]->critical->text)
631 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr)-strlen(perfstr)-1);
589 } 632 }
590 633
591 if (type)
592 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
593 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1); 634 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
594 } 635 }
595 } 636 }
@@ -601,7 +642,7 @@ main (int argc, char **argv)
601 state_string=malloc(string_length); 642 state_string=malloc(string_length);
602 if(state_string==NULL) 643 if(state_string==NULL)
603 die(STATE_UNKNOWN, _("Cannot malloc")); 644 die(STATE_UNKNOWN, _("Cannot malloc"));
604 645
605 current_length=0; 646 current_length=0;
606 for(i=0; i<total_oids; i++) { 647 for(i=0; i<total_oids; i++) {
607 xasprintf(&temp_string,"%.0f",response_value[i]); 648 xasprintf(&temp_string,"%.0f",response_value[i]);
@@ -623,7 +664,7 @@ main (int argc, char **argv)
623 state_string[--current_length]='\0'; 664 state_string[--current_length]='\0';
624 if (verbose > 2) 665 if (verbose > 2)
625 printf("State string=%s\n",state_string); 666 printf("State string=%s\n",state_string);
626 667
627 /* This is not strictly the same as time now, but any subtle variations will cancel out */ 668 /* This is not strictly the same as time now, but any subtle variations will cancel out */
628 np_state_write_string(current_time, state_string ); 669 np_state_write_string(current_time, state_string );
629 if(previous_state==NULL) { 670 if(previous_state==NULL) {
@@ -655,6 +696,7 @@ process_arguments (int argc, char **argv)
655 {"oid", required_argument, 0, 'o'}, 696 {"oid", required_argument, 0, 'o'},
656 {"object", required_argument, 0, 'o'}, 697 {"object", required_argument, 0, 'o'},
657 {"delimiter", required_argument, 0, 'd'}, 698 {"delimiter", required_argument, 0, 'd'},
699 {"nulloid", required_argument, 0, 'z'},
658 {"output-delimiter", required_argument, 0, 'D'}, 700 {"output-delimiter", required_argument, 0, 'D'},
659 {"string", required_argument, 0, 's'}, 701 {"string", required_argument, 0, 's'},
660 {"timeout", required_argument, 0, 't'}, 702 {"timeout", required_argument, 0, 't'},
@@ -682,6 +724,9 @@ process_arguments (int argc, char **argv)
682 {"perf-oids", no_argument, 0, 'O'}, 724 {"perf-oids", no_argument, 0, 'O'},
683 {"ipv4", no_argument, 0, '4'}, 725 {"ipv4", no_argument, 0, '4'},
684 {"ipv6", no_argument, 0, '6'}, 726 {"ipv6", no_argument, 0, '6'},
727 {"multiplier", required_argument, 0, 'M'},
728 {"fmtstr", required_argument, 0, 'f'},
729 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
685 {0, 0, 0, 0} 730 {0, 0, 0, 0}
686 }; 731 };
687 732
@@ -699,7 +744,7 @@ process_arguments (int argc, char **argv)
699 } 744 }
700 745
701 while (1) { 746 while (1) {
702 c = 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:", 747 c = 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:",
703 longopts, &option); 748 longopts, &option);
704 749
705 if (c == -1 || c == EOF) 750 if (c == -1 || c == EOF)
@@ -810,6 +855,12 @@ process_arguments (int argc, char **argv)
810 eval_method[j+1] |= CRIT_PRESENT; 855 eval_method[j+1] |= CRIT_PRESENT;
811 } 856 }
812 break; 857 break;
858 case 'z': /* Null OID Return Check */
859 if (!is_integer (optarg))
860 usage2 (_("Exit status must be a positive integer"), optarg);
861 else
862 nulloid = atoi(optarg);
863 break;
813 case 's': /* string or substring */ 864 case 's': /* string or substring */
814 strncpy (string_value, optarg, sizeof (string_value) - 1); 865 strncpy (string_value, optarg, sizeof (string_value) - 1);
815 string_value[sizeof (string_value) - 1] = 0; 866 string_value[sizeof (string_value) - 1] = 0;
@@ -823,6 +874,7 @@ process_arguments (int argc, char **argv)
823 break; 874 break;
824 case 'R': /* regex */ 875 case 'R': /* regex */
825 cflags = REG_ICASE; 876 cflags = REG_ICASE;
877 // fall through
826 case 'r': /* regex */ 878 case 'r': /* regex */
827 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 879 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
828 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1); 880 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
@@ -931,6 +983,19 @@ process_arguments (int argc, char **argv)
931 if(verbose>2) 983 if(verbose>2)
932 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); 984 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n");
933 break; 985 break;
986 case 'M':
987 if ( strspn( optarg, "0123456789.," ) == strlen( optarg ) ) {
988 multiplier=strtod(optarg,NULL);
989 }
990 break;
991 case 'f':
992 if (multiplier != 1.0) {
993 fmtstr=optarg;
994 fmtstr_set = true;
995 }
996 break;
997 case L_IGNORE_MIB_PARSING_ERRORS:
998 ignore_mib_parsing_errors = true;
934 } 999 }
935 } 1000 }
936 1001
@@ -1000,7 +1065,7 @@ validate_arguments ()
1000 contextargs[0] = strdup ("-n"); 1065 contextargs[0] = strdup ("-n");
1001 contextargs[1] = strdup (context); 1066 contextargs[1] = strdup (context);
1002 } 1067 }
1003 1068
1004 if (seclevel == NULL) 1069 if (seclevel == NULL)
1005 xasprintf(&seclevel, "noAuthNoPriv"); 1070 xasprintf(&seclevel, "noAuthNoPriv");
1006 1071
@@ -1121,6 +1186,44 @@ nextarg (char *str)
1121 1186
1122 1187
1123 1188
1189/* multiply result (values 0 < n < 1 work as divider) */
1190char *
1191multiply (char *str)
1192{
1193 char *endptr;
1194 double val;
1195 char *conv = "%f";
1196
1197 if(multiplier == 1)
1198 return(str);
1199
1200 if(verbose>2)
1201 printf(" multiply input: %s\n", str);
1202
1203 val = strtod (str, &endptr);
1204 if ((val == 0.0) && (endptr == str)) {
1205 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
1206 }
1207
1208 if(verbose>2)
1209 printf(" multiply extracted double: %f\n", val);
1210 val *= multiplier;
1211 if (fmtstr_set) {
1212 conv = fmtstr;
1213 }
1214 if (val == (int)val) {
1215 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1216 } else {
1217 if(verbose>2)
1218 printf(" multiply using format: %s\n", conv);
1219 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1220 }
1221 if(verbose>2)
1222 printf(" multiply result: %s\n", buffer);
1223 return buffer;
1224}
1225
1226
1124void 1227void
1125print_help (void) 1228print_help (void)
1126{ 1229{
@@ -1160,7 +1263,7 @@ print_help (void)
1160 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY); 1263 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
1161 printf (" %s\n", "-U, --secname=USERNAME"); 1264 printf (" %s\n", "-U, --secname=USERNAME");
1162 printf (" %s\n", _("SNMPv3 username")); 1265 printf (" %s\n", _("SNMPv3 username"));
1163 printf (" %s\n", "-A, --authpassword=PASSWORD"); 1266 printf (" %s\n", "-A, --authpasswd=PASSWORD");
1164 printf (" %s\n", _("SNMPv3 authentication password")); 1267 printf (" %s\n", _("SNMPv3 authentication password"));
1165 printf (" %s\n", "-X, --privpasswd=PASSWORD"); 1268 printf (" %s\n", "-X, --privpasswd=PASSWORD");
1166 printf (" %s\n", _("SNMPv3 privacy password")); 1269 printf (" %s\n", _("SNMPv3 privacy password"));
@@ -1175,6 +1278,14 @@ print_help (void)
1175 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); 1278 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1176 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered")); 1279 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1177 printf (" %s\n", _("to be the data that should be used in the evaluation.")); 1280 printf (" %s\n", _("to be the data that should be used in the evaluation."));
1281 printf (" %s\n", "-z, --nulloid=#");
1282 printf (" %s\n", _("If the check returns a 0 length string or NULL value"));
1283 printf (" %s\n", _("This option allows you to choose what status you want it to exit"));
1284 printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1285 printf (" %s\n", _("0 = OK"));
1286 printf (" %s\n", _("1 = WARNING"));
1287 printf (" %s\n", _("2 = CRITICAL"));
1288 printf (" %s\n", _("3 = UNKNOWN"));
1178 1289
1179 /* Tests Against Integers */ 1290 /* Tests Against Integers */
1180 printf (" %s\n", "-w, --warning=THRESHOLD(s)"); 1291 printf (" %s\n", "-w, --warning=THRESHOLD(s)");
@@ -1186,7 +1297,7 @@ print_help (void)
1186 printf (" %s\n", "--rate-multiplier"); 1297 printf (" %s\n", "--rate-multiplier");
1187 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute")); 1298 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1188 printf (" %s\n", "--offset=OFFSET"); 1299 printf (" %s\n", "--offset=OFFSET");
1189 printf (" %s\n", _("Add/substract the specified OFFSET to numeric sensor data")); 1300 printf (" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1190 1301
1191 /* Tests Against Strings */ 1302 /* Tests Against Strings */
1192 printf (" %s\n", "-s, --string=STRING"); 1303 printf (" %s\n", "-s, --string=STRING");
@@ -1205,14 +1316,22 @@ print_help (void)
1205 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); 1316 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1206 printf (" %s\n", "-D, --output-delimiter=STRING"); 1317 printf (" %s\n", "-D, --output-delimiter=STRING");
1207 printf (" %s\n", _("Separates output on multiple OID requests")); 1318 printf (" %s\n", _("Separates output on multiple OID requests"));
1319 printf (" %s\n", "-M, --multiplier=FLOAT");
1320 printf (" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1321 printf (" %s\n", "-f, --fmtstr=STRING");
1322 printf (" %s\n", _("C-style format string for float values (see option -M)"));
1208 1323
1209 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1324 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1325 printf (" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
1210 printf (" %s\n", "-e, --retries=INTEGER"); 1326 printf (" %s\n", "-e, --retries=INTEGER");
1211 printf (" %s\n", _("Number of retries to be used in the requests")); 1327 printf (" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES);
1212 1328
1213 printf (" %s\n", "-O, --perf-oids"); 1329 printf (" %s\n", "-O, --perf-oids");
1214 printf (" %s\n", _("Label performance data with OIDs instead of --label's")); 1330 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1215 1331
1332 printf (" %s\n", "--ignore-mib-parsing-errors");
1333 printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1334
1216 printf (UT_VERBOSE); 1335 printf (UT_VERBOSE);
1217 1336
1218 printf ("\n"); 1337 printf ("\n");
@@ -1256,4 +1375,5 @@ print_usage (void)
1256 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n"); 1375 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1257 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n"); 1376 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1258 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n"); 1377 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1378 printf ("[-M multiplier [-f format]]\n");
1259} 1379}
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index 4d5a407..cd965e3 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -1,30 +1,30 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_swap plugin 3* Monitoring check_swap plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net) 6* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
7* Copyright (c) 2000-2007 Monitoring Plugins Development Team 7* Copyright (c) 2000-2007 Monitoring Plugins Development Team
8* 8*
9* Description: 9* Description:
10* 10*
11* This file contains the check_swap plugin 11* This file contains the check_swap plugin
12* 12*
13* 13*
14* This program is free software: you can redistribute it and/or modify 14* This program is free software: you can redistribute it and/or modify
15* it under the terms of the GNU General Public License as published by 15* it under the terms of the GNU General Public License as published by
16* the Free Software Foundation, either version 3 of the License, or 16* the Free Software Foundation, either version 3 of the License, or
17* (at your option) any later version. 17* (at your option) any later version.
18* 18*
19* This program is distributed in the hope that it will be useful, 19* This program is distributed in the hope that it will be useful,
20* but WITHOUT ANY WARRANTY; without even the implied warranty of 20* but WITHOUT ANY WARRANTY; without even the implied warranty of
21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22* GNU General Public License for more details. 22* GNU General Public License for more details.
23* 23*
24* You should have received a copy of the GNU General Public License 24* You should have received a copy of the GNU General Public License
25* along with this program. If not, see <http://www.gnu.org/licenses/>. 25* along with this program. If not, see <http://www.gnu.org/licenses/>.
26* 26*
27* 27*
28*****************************************************************************/ 28*****************************************************************************/
29 29
30const char *progname = "check_swap"; 30const char *progname = "check_swap";
@@ -51,16 +51,19 @@ const char *email = "devel@monitoring-plugins.org";
51# define SWAP_CONVERSION 1 51# define SWAP_CONVERSION 1
52#endif 52#endif
53 53
54int check_swap (int usp, float free_swap_mb); 54typedef struct {
55 int is_percentage;
56 uint64_t value;
57} threshold_t;
58
59int check_swap (float free_swap_mb, float total_swap_mb);
55int process_arguments (int argc, char **argv); 60int process_arguments (int argc, char **argv);
56int validate_arguments (void); 61int validate_arguments (void);
57void print_usage (void); 62void print_usage (void);
58void print_help (void); 63void print_help (void);
59 64
60int warn_percent = 0; 65threshold_t warn;
61int crit_percent = 0; 66threshold_t crit;
62float warn_size_bytes = 0;
63float crit_size_bytes = 0;
64int verbose; 67int verbose;
65int allswaps; 68int allswaps;
66int no_swap_state = STATE_CRITICAL; 69int no_swap_state = STATE_CRITICAL;
@@ -68,9 +71,10 @@ int no_swap_state = STATE_CRITICAL;
68int 71int
69main (int argc, char **argv) 72main (int argc, char **argv)
70{ 73{
71 int percent_used, percent; 74 unsigned int percent_used, percent;
72 float total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0; 75 uint64_t total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
73 float dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0, tmp_mb = 0; 76 uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0;
77 uint64_t tmp_KB = 0;
74 int result = STATE_UNKNOWN; 78 int result = STATE_UNKNOWN;
75 char input_buffer[MAX_INPUT_BUFFER]; 79 char input_buffer[MAX_INPUT_BUFFER];
76#ifdef HAVE_PROC_MEMINFO 80#ifdef HAVE_PROC_MEMINFO
@@ -116,10 +120,15 @@ main (int argc, char **argv)
116 } 120 }
117 fp = fopen (PROC_MEMINFO, "r"); 121 fp = fopen (PROC_MEMINFO, "r");
118 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) { 122 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
119 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %f %f %f", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) { 123 /*
120 dsktotal_mb = dsktotal_mb / 1048576; /* Apply conversion */ 124 * The following sscanf call looks for a line looking like: "Swap: 123 123 123"
121 dskused_mb = dskused_mb / 1048576; 125 * On which kind of system this format exists, I can not say, but I wanted to
122 dskfree_mb = dskfree_mb / 1048576; 126 * document this for people who are not adapt with sscanf anymore, like me
127 */
128 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
129 dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */
130 dskused_mb = dskused_mb / (1024 * 1024);
131 dskfree_mb = dskfree_mb / (1024 * 1024);
123 total_swap_mb += dsktotal_mb; 132 total_swap_mb += dsktotal_mb;
124 used_swap_mb += dskused_mb; 133 used_swap_mb += dskused_mb;
125 free_swap_mb += dskfree_mb; 134 free_swap_mb += dskfree_mb;
@@ -128,21 +137,29 @@ main (int argc, char **argv)
128 percent=100.0; 137 percent=100.0;
129 else 138 else
130 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb)); 139 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
131 result = max_state (result, check_swap (percent, dskfree_mb)); 140 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
132 if (verbose) 141 if (verbose)
133 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent); 142 xasprintf (&status, "%s [%lu (%d%%)]", status, dskfree_mb, 100 - percent);
134 } 143 }
135 } 144 }
136 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFre]%*[:] %f %*[k]%*[B]", str, &tmp_mb)) { 145
146 /*
147 * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123"
148 * This format exists at least on Debian Linux with a 5.* kernel
149 */
150 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) {
137 if (verbose >= 3) { 151 if (verbose >= 3) {
138 printf("Got %s with %f\n", str, tmp_mb); 152 printf("Got %s with %lu\n", str, tmp_KB);
139 } 153 }
140 /* I think this part is always in Kb, so convert to mb */ 154 /* I think this part is always in Kb, so convert to mb */
141 if (strcmp ("Total", str) == 0) { 155 if (strcmp ("Total", str) == 0) {
142 dsktotal_mb = tmp_mb / 1024; 156 dsktotal_mb = tmp_KB / 1024;
143 } 157 }
144 else if (strcmp ("Free", str) == 0) { 158 else if (strcmp ("Free", str) == 0) {
145 dskfree_mb = tmp_mb / 1024; 159 dskfree_mb = dskfree_mb + tmp_KB / 1024;
160 }
161 else if (strcmp ("Cached", str) == 0) {
162 dskfree_mb = dskfree_mb + tmp_KB / 1024;
146 } 163 }
147 } 164 }
148 } 165 }
@@ -161,7 +178,7 @@ main (int argc, char **argv)
161# ifdef _AIX 178# ifdef _AIX
162 if (!allswaps) { 179 if (!allswaps) {
163 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s"); 180 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
164 xasprintf(&swap_format, "%s", "%f%*s %f"); 181 xasprintf(&swap_format, "%s", "%lu%*s %lu");
165 conv_factor = 1; 182 conv_factor = 1;
166 } 183 }
167# endif 184# endif
@@ -188,9 +205,9 @@ main (int argc, char **argv)
188 temp_buffer = strtok (input_buffer, " \n"); 205 temp_buffer = strtok (input_buffer, " \n");
189 while (temp_buffer) { 206 while (temp_buffer) {
190 if (strstr (temp_buffer, "blocks")) 207 if (strstr (temp_buffer, "blocks"))
191 sprintf (str, "%s %s", str, "%f"); 208 sprintf (str, "%s %s", str, "%lu");
192 else if (strstr (temp_buffer, "dskfree")) 209 else if (strstr (temp_buffer, "dskfree"))
193 sprintf (str, "%s %s", str, "%f"); 210 sprintf (str, "%s %s", str, "%lu");
194 else 211 else
195 sprintf (str, "%s %s", str, "%*s"); 212 sprintf (str, "%s %s", str, "%*s");
196 temp_buffer = strtok (NULL, " \n"); 213 temp_buffer = strtok (NULL, " \n");
@@ -227,7 +244,7 @@ main (int argc, char **argv)
227 free_swap_mb += dskfree_mb; 244 free_swap_mb += dskfree_mb;
228 if (allswaps) { 245 if (allswaps) {
229 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb)); 246 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
230 result = max_state (result, check_swap (percent, dskfree_mb)); 247 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
231 if (verbose) 248 if (verbose)
232 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent); 249 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
233 } 250 }
@@ -289,7 +306,7 @@ main (int argc, char **argv)
289 306
290 if(allswaps && dsktotal_mb > 0){ 307 if(allswaps && dsktotal_mb > 0){
291 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb)); 308 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
292 result = max_state (result, check_swap (percent, dskfree_mb)); 309 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
293 if (verbose) { 310 if (verbose) {
294 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent); 311 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
295 } 312 }
@@ -328,7 +345,7 @@ main (int argc, char **argv)
328 345
329 if(allswaps && dsktotal_mb > 0){ 346 if(allswaps && dsktotal_mb > 0){
330 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb)); 347 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
331 result = max_state (result, check_swap (percent, dskfree_mb)); 348 result = max_state (result, check_swap(dskfree_mb, dsktotal_mb));
332 if (verbose) { 349 if (verbose) {
333 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent); 350 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
334 } 351 }
@@ -355,41 +372,55 @@ main (int argc, char **argv)
355 status = "- Swap is either disabled, not present, or of zero size. "; 372 status = "- Swap is either disabled, not present, or of zero size. ";
356 } 373 }
357 374
358 result = max_state (result, check_swap (percent_used, free_swap_mb)); 375 result = max_state (result, check_swap(free_swap_mb, total_swap_mb));
359 printf (_("SWAP %s - %d%% free (%d MB out of %d MB) %s|"), 376 printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"),
360 state_text (result), 377 state_text (result),
361 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status); 378 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
362 379
363 puts (perfdata ("swap", (long) free_swap_mb, "MB", 380 uint64_t warn_print = warn.value;
364 TRUE, (long) max (warn_size_bytes/(1024 * 1024), warn_percent/100.0*total_swap_mb), 381 if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100);
365 TRUE, (long) max (crit_size_bytes/(1024 * 1024), crit_percent/100.0*total_swap_mb), 382 uint64_t crit_print = crit.value;
383 if (crit.is_percentage) crit_print = crit.value * (total_swap_mb *1024 *1024/100);
384
385 puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B",
386 TRUE, warn_print,
387 TRUE, crit_print,
366 TRUE, 0, 388 TRUE, 0,
367 TRUE, (long) total_swap_mb)); 389 TRUE, (long) total_swap_mb * 1024 * 1024));
368 390
369 return result; 391 return result;
370} 392}
371 393
372 394
373
374int 395int
375check_swap (int usp, float free_swap_mb) 396check_swap(float free_swap_mb, float total_swap_mb)
376{ 397{
377 398
378 if (!free_swap_mb) return no_swap_state; 399 if (!total_swap_mb) return no_swap_state;
379 400
380 int result = STATE_UNKNOWN; 401 uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */
381 float free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */ 402
382 if (usp >= 0 && crit_percent != 0 && usp >= (100.0 - crit_percent)) 403 if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL;
383 result = STATE_CRITICAL; 404 if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
384 else if (crit_size_bytes > 0 && free_swap <= crit_size_bytes) 405
385 result = STATE_CRITICAL; 406
386 else if (usp >= 0 && warn_percent != 0 && usp >= (100.0 - warn_percent)) 407 uint64_t usage_percentage = ((total_swap_mb - free_swap_mb) / total_swap_mb) * 100;
387 result = STATE_WARNING; 408
388 else if (warn_size_bytes > 0 && free_swap <= warn_size_bytes) 409 if (crit.is_percentage &&
389 result = STATE_WARNING; 410 crit.value != 0 &&
390 else if (usp >= 0.0) 411 usage_percentage >= (100 - crit.value))
391 result = STATE_OK; 412 {
392 return result; 413 return STATE_CRITICAL;
414 }
415
416 if (warn.is_percentage &&
417 warn.value != 0 &&
418 usage_percentage >= (100 - warn.value))
419 {
420 return STATE_WARNING;
421 }
422
423 return STATE_OK;
393} 424}
394 425
395 426
@@ -422,42 +453,66 @@ process_arguments (int argc, char **argv)
422 break; 453 break;
423 454
424 switch (c) { 455 switch (c) {
425 case 'w': /* warning size threshold */ 456 case 'w': /* warning size threshold */
426 if (is_intnonneg (optarg)) { 457 {
427 warn_size_bytes = (float) atoi (optarg); 458 /*
428 break; 459 * We expect either a positive integer value without a unit, which means
429 } 460 * the unit is Bytes or a positive integer value and a percentage sign (%),
430 else if (strstr (optarg, ",") && 461 * which means the value must be with 0 and 100 and is relative to the total swap
431 strstr (optarg, "%") && 462 */
432 sscanf (optarg, "%f,%d%%", &warn_size_bytes, &warn_percent) == 2) { 463 size_t length;
433 warn_size_bytes = floorf(warn_size_bytes); 464 length = strlen(optarg);
434 break; 465
435 } 466 if (optarg[length - 1] == '%') {
436 else if (strstr (optarg, "%") && 467 /* It's percentage */
437 sscanf (optarg, "%d%%", &warn_percent) == 1) { 468 warn.is_percentage = 1;
438 break; 469 optarg[length - 1] = '\0';
439 } 470 if (is_uint64(optarg, &warn.value)) {
440 else { 471 if (warn.value > 100) {
441 usage4 (_("Warning threshold must be integer or percentage!")); 472 usage4 (_("Warning threshold percentage must be <= 100!"));
442 } 473 }
443 case 'c': /* critical size threshold */ 474 }
444 if (is_intnonneg (optarg)) { 475 break;
445 crit_size_bytes = (float) atoi (optarg); 476 } else {
446 break; 477 /* It's Bytes */
447 } 478 warn.is_percentage = 0;
448 else if (strstr (optarg, ",") && 479 if (is_uint64(optarg, &warn.value)) {
449 strstr (optarg, "%") && 480 break;
450 sscanf (optarg, "%f,%d%%", &crit_size_bytes, &crit_percent) == 2) { 481 } else {
451 crit_size_bytes = floorf(crit_size_bytes); 482 usage4 (_("Warning threshold be positive integer or percentage!"));
452 break; 483 }
453 } 484 }
454 else if (strstr (optarg, "%") &&
455 sscanf (optarg, "%d%%", &crit_percent) == 1) {
456 break;
457 }
458 else {
459 usage4 (_("Critical threshold must be integer or percentage!"));
460 } 485 }
486 case 'c': /* critical size threshold */
487 {
488 /*
489 * We expect either a positive integer value without a unit, which means
490 * the unit is Bytes or a positive integer value and a percentage sign (%),
491 * which means the value must be with 0 and 100 and is relative to the total swap
492 */
493 size_t length;
494 length = strlen(optarg);
495
496 if (optarg[length - 1] == '%') {
497 /* It's percentage */
498 crit.is_percentage = 1;
499 optarg[length - 1] = '\0';
500 if (is_uint64(optarg, &crit.value)) {
501 if (crit.value> 100) {
502 usage4 (_("Critical threshold percentage must be <= 100!"));
503 }
504 }
505 break;
506 } else {
507 /* It's Bytes */
508 crit.is_percentage = 0;
509 if (is_uint64(optarg, &crit.value)) {
510 break;
511 } else {
512 usage4 (_("Critical threshold be positive integer or percentage!"));
513 }
514 }
515 }
461 case 'a': /* all swap */ 516 case 'a': /* all swap */
462 allswaps = TRUE; 517 allswaps = TRUE;
463 break; 518 break;
@@ -465,6 +520,7 @@ process_arguments (int argc, char **argv)
465 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) { 520 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) {
466 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 521 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
467 } 522 }
523 break;
468 case 'v': /* verbose */ 524 case 'v': /* verbose */
469 verbose++; 525 verbose++;
470 break; 526 break;
@@ -482,23 +538,6 @@ process_arguments (int argc, char **argv)
482 c = optind; 538 c = optind;
483 if (c == argc) 539 if (c == argc)
484 return validate_arguments (); 540 return validate_arguments ();
485 if (warn_percent == 0 && is_intnonneg (argv[c]))
486 warn_percent = atoi (argv[c++]);
487
488 if (c == argc)
489 return validate_arguments ();
490 if (crit_percent == 0 && is_intnonneg (argv[c]))
491 crit_percent = atoi (argv[c++]);
492
493 if (c == argc)
494 return validate_arguments ();
495 if (warn_size_bytes == 0 && is_intnonneg (argv[c]))
496 warn_size_bytes = (float) atoi (argv[c++]);
497
498 if (c == argc)
499 return validate_arguments ();
500 if (crit_size_bytes == 0 && is_intnonneg (argv[c]))
501 crit_size_bytes = (float) atoi (argv[c++]);
502 541
503 return validate_arguments (); 542 return validate_arguments ();
504} 543}
@@ -508,17 +547,15 @@ process_arguments (int argc, char **argv)
508int 547int
509validate_arguments (void) 548validate_arguments (void)
510{ 549{
511 if (warn_percent == 0 && crit_percent == 0 && warn_size_bytes == 0 550 if (warn.value == 0 && crit.value == 0) {
512 && crit_size_bytes == 0) {
513 return ERROR; 551 return ERROR;
514 } 552 }
515 else if (warn_percent < crit_percent) { 553 else if ((warn.is_percentage == crit.is_percentage) && (warn.value < crit.value)) {
516 usage4 554 /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
517 (_("Warning percentage should be more than critical percentage")); 555 * and crit is absolute. We cannot determine the condition at this point since we
518 } 556 * dont know the value of total swap yet
519 else if (warn_size_bytes < crit_size_bytes) { 557 */
520 usage4 558 usage4(_("Warning should be more than critical"));
521 (_("Warning free space should be more than critical free space"));
522 } 559 }
523 return OK; 560 return OK;
524} 561}
@@ -534,7 +571,7 @@ print_help (void)
534 571
535 printf ("%s\n", _("Check swap space on local machine.")); 572 printf ("%s\n", _("Check swap space on local machine."));
536 573
537 printf ("\n\n"); 574 printf ("\n\n");
538 575
539 print_usage (); 576 print_usage ();
540 577
@@ -542,33 +579,32 @@ print_help (void)
542 printf (UT_EXTRA_OPTS); 579 printf (UT_EXTRA_OPTS);
543 580
544 printf (" %s\n", "-w, --warning=INTEGER"); 581 printf (" %s\n", "-w, --warning=INTEGER");
545 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free")); 582 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
546 printf (" %s\n", "-w, --warning=PERCENT%%"); 583 printf (" %s\n", "-w, --warning=PERCENT%");
547 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free")); 584 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
548 printf (" %s\n", "-c, --critical=INTEGER"); 585 printf (" %s\n", "-c, --critical=INTEGER");
549 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free")); 586 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
550 printf (" %s\n", "-c, --critical=PERCENT%%"); 587 printf (" %s\n", "-c, --critical=PERCENT%");
551 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free")); 588 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
552 printf (" %s\n", "-a, --allswaps"); 589 printf (" %s\n", "-a, --allswaps");
553 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one")); 590 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
554 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>"); 591 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
555 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state)); 592 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state));
556 printf (UT_VERBOSE); 593 printf (UT_VERBOSE);
557 594
558 printf ("\n"); 595 printf ("\n");
559 printf ("%s\n", _("Notes:")); 596 printf ("%s\n", _("Notes:"));
560 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked.")); 597 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
561 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s.")); 598 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
562 599
563 printf (UT_SUPPORT); 600 printf (UT_SUPPORT);
564} 601}
565 602
566 603
567
568void 604void
569print_usage (void) 605print_usage (void)
570{ 606{
571 printf ("%s\n", _("Usage:")); 607 printf ("%s\n", _("Usage:"));
572 printf (" %s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname); 608 printf (" %s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
573 printf (" -w <bytes_free> -c <bytes_free> [-n <state>]\n"); 609 printf (" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
574} 610}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 61333bd..1d307cf 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -86,6 +86,11 @@ static char buffer[MAXBUF];
86static int expect_mismatch_state = STATE_WARNING; 86static int expect_mismatch_state = STATE_WARNING;
87static int match_flags = NP_MATCH_EXACT; 87static int match_flags = NP_MATCH_EXACT;
88 88
89#ifdef HAVE_SSL
90static char *sni = NULL;
91static int sni_specified = FALSE;
92#endif
93
89#define FLAG_SSL 0x01 94#define FLAG_SSL 0x01
90#define FLAG_VERBOSE 0x02 95#define FLAG_VERBOSE 0x02
91#define FLAG_TIME_WARN 0x04 96#define FLAG_TIME_WARN 0x04
@@ -123,7 +128,7 @@ main (int argc, char **argv)
123 SERVICE[i] = toupper(SERVICE[i]); 128 SERVICE[i] = toupper(SERVICE[i]);
124 } 129 }
125 130
126 /* set up a resonable buffer at first (will be realloc()'ed if 131 /* set up a reasonable buffer at first (will be realloc()'ed if
127 * user specifies other options) */ 132 * user specifies other options) */
128 server_expect = calloc(sizeof(char *), 2); 133 server_expect = calloc(sizeof(char *), 2);
129 134
@@ -241,7 +246,7 @@ main (int argc, char **argv)
241 246
242#ifdef HAVE_SSL 247#ifdef HAVE_SSL
243 if (flags & FLAG_SSL){ 248 if (flags & FLAG_SSL){
244 result = np_net_ssl_init(sd); 249 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL));
245 if (result == STATE_OK && check_cert == TRUE) { 250 if (result == STATE_OK && check_cert == TRUE) {
246 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 251 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
247 } 252 }
@@ -401,6 +406,10 @@ process_arguments (int argc, char **argv)
401 int escape = 0; 406 int escape = 0;
402 char *temp; 407 char *temp;
403 408
409 enum {
410 SNI_OPTION = CHAR_MAX + 1
411 };
412
404 int option = 0; 413 int option = 0;
405 static struct option longopts[] = { 414 static struct option longopts[] = {
406 {"hostname", required_argument, 0, 'H'}, 415 {"hostname", required_argument, 0, 'H'},
@@ -427,6 +436,7 @@ process_arguments (int argc, char **argv)
427 {"version", no_argument, 0, 'V'}, 436 {"version", no_argument, 0, 'V'},
428 {"help", no_argument, 0, 'h'}, 437 {"help", no_argument, 0, 'h'},
429 {"ssl", no_argument, 0, 'S'}, 438 {"ssl", no_argument, 0, 'S'},
439 {"sni", required_argument, 0, SNI_OPTION},
430 {"certificate", required_argument, 0, 'D'}, 440 {"certificate", required_argument, 0, 'D'},
431 {0, 0, 0, 0} 441 {0, 0, 0, 0}
432 }; 442 };
@@ -604,6 +614,15 @@ process_arguments (int argc, char **argv)
604 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 614 die (STATE_UNKNOWN, _("Invalid option - SSL is not available"));
605#endif 615#endif
606 break; 616 break;
617 case SNI_OPTION:
618#ifdef HAVE_SSL
619 flags |= FLAG_SSL;
620 sni_specified = TRUE;
621 sni = optarg;
622#else
623 die (STATE_UNKNOWN, _("Invalid option - SSL is not available"));
624#endif
625 break;
607 case 'A': 626 case 'A':
608 match_flags |= NP_MATCH_ALL; 627 match_flags |= NP_MATCH_ALL;
609 break; 628 break;
@@ -671,6 +690,8 @@ print_help (void)
671 printf (" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0).")); 690 printf (" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0)."));
672 printf (" %s\n", "-S, --ssl"); 691 printf (" %s\n", "-S, --ssl");
673 printf (" %s\n", _("Use SSL for the connection.")); 692 printf (" %s\n", _("Use SSL for the connection."));
693 printf (" %s\n", "--sni=STRING");
694 printf (" %s\n", _("SSL server_name"));
674#endif 695#endif
675 696
676 printf (UT_WARN_CRIT); 697 printf (UT_WARN_CRIT);
diff --git a/plugins/check_ups.c b/plugins/check_ups.c
index e9e56a5..68737c4 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -89,7 +89,7 @@ char *ups_status;
89int temp_output_c = 0; 89int temp_output_c = 0;
90 90
91int determine_status (void); 91int determine_status (void);
92int get_ups_variable (const char *, char *, size_t); 92int get_ups_variable (const char *, char *);
93 93
94int process_arguments (int, char **); 94int process_arguments (int, char **);
95int validate_arguments (void); 95int validate_arguments (void);
@@ -189,7 +189,7 @@ main (int argc, char **argv)
189 } 189 }
190 190
191 /* get the ups utility voltage if possible */ 191 /* get the ups utility voltage if possible */
192 res=get_ups_variable ("input.voltage", temp_buffer, sizeof (temp_buffer)); 192 res=get_ups_variable ("input.voltage", temp_buffer);
193 if (res == NOSUCHVAR) supported_options &= ~UPS_UTILITY; 193 if (res == NOSUCHVAR) supported_options &= ~UPS_UTILITY;
194 else if (res != OK) 194 else if (res != OK)
195 return STATE_CRITICAL; 195 return STATE_CRITICAL;
@@ -224,7 +224,7 @@ main (int argc, char **argv)
224 } 224 }
225 225
226 /* get the ups battery percent if possible */ 226 /* get the ups battery percent if possible */
227 res=get_ups_variable ("battery.charge", temp_buffer, sizeof (temp_buffer)); 227 res=get_ups_variable ("battery.charge", temp_buffer);
228 if (res == NOSUCHVAR) supported_options &= ~UPS_BATTPCT; 228 if (res == NOSUCHVAR) supported_options &= ~UPS_BATTPCT;
229 else if ( res != OK) 229 else if ( res != OK)
230 return STATE_CRITICAL; 230 return STATE_CRITICAL;
@@ -253,7 +253,7 @@ main (int argc, char **argv)
253 } 253 }
254 254
255 /* get the ups load percent if possible */ 255 /* get the ups load percent if possible */
256 res=get_ups_variable ("ups.load", temp_buffer, sizeof (temp_buffer)); 256 res=get_ups_variable ("ups.load", temp_buffer);
257 if ( res == NOSUCHVAR ) supported_options &= ~UPS_LOADPCT; 257 if ( res == NOSUCHVAR ) supported_options &= ~UPS_LOADPCT;
258 else if ( res != OK) 258 else if ( res != OK)
259 return STATE_CRITICAL; 259 return STATE_CRITICAL;
@@ -282,7 +282,7 @@ main (int argc, char **argv)
282 } 282 }
283 283
284 /* get the ups temperature if possible */ 284 /* get the ups temperature if possible */
285 res=get_ups_variable ("ups.temperature", temp_buffer, sizeof (temp_buffer)); 285 res=get_ups_variable ("ups.temperature", temp_buffer);
286 if ( res == NOSUCHVAR ) supported_options &= ~UPS_TEMP; 286 if ( res == NOSUCHVAR ) supported_options &= ~UPS_TEMP;
287 else if ( res != OK) 287 else if ( res != OK)
288 return STATE_CRITICAL; 288 return STATE_CRITICAL;
@@ -342,7 +342,7 @@ determine_status (void)
342 char *ptr; 342 char *ptr;
343 int res; 343 int res;
344 344
345 res=get_ups_variable ("ups.status", recv_buffer, sizeof (recv_buffer)); 345 res=get_ups_variable ("ups.status", recv_buffer);
346 if (res == NOSUCHVAR) return OK; 346 if (res == NOSUCHVAR) return OK;
347 if (res != STATE_OK) { 347 if (res != STATE_OK) {
348 printf ("%s\n", _("Invalid response received from host")); 348 printf ("%s\n", _("Invalid response received from host"));
@@ -388,7 +388,7 @@ determine_status (void)
388 388
389/* gets a variable value for a specific UPS */ 389/* gets a variable value for a specific UPS */
390int 390int
391get_ups_variable (const char *varname, char *buf, size_t buflen) 391get_ups_variable (const char *varname, char *buf)
392{ 392{
393 /* char command[MAX_INPUT_BUFFER]; */ 393 /* char command[MAX_INPUT_BUFFER]; */
394 char temp_buffer[MAX_INPUT_BUFFER]; 394 char temp_buffer[MAX_INPUT_BUFFER];
@@ -402,7 +402,10 @@ get_ups_variable (const char *varname, char *buf, size_t buflen)
402 402
403 /* create the command string to send to the UPS daemon */ 403 /* create the command string to send to the UPS daemon */
404 /* Add LOGOUT to avoid read failure logs */ 404 /* Add LOGOUT to avoid read failure logs */
405 sprintf (send_buffer, "GET VAR %s %s\nLOGOUT\n", ups_name, varname); 405 if (snprintf (send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", ups_name, varname) >= sizeof(send_buffer)) {
406 printf("%s\n", _("UPS name to long for buffer"));
407 return ERROR;
408 }
406 409
407 /* send the command to the daemon and get a response back */ 410 /* send the command to the daemon and get a response back */
408 if (process_tcp_request 411 if (process_tcp_request
@@ -504,7 +507,7 @@ process_arguments (int argc, char **argv)
504 usage2 (_("Invalid hostname/address"), optarg); 507 usage2 (_("Invalid hostname/address"), optarg);
505 } 508 }
506 break; 509 break;
507 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Farenheit) */ 510 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Fahrenheit) */
508 temp_output_c = 1; 511 temp_output_c = 1;
509 break; 512 break;
510 case 'u': /* ups name */ 513 case 'u': /* ups name */
diff --git a/plugins/check_users.c b/plugins/check_users.c
index f6f4b36..2a9ee98 100644
--- a/plugins/check_users.c
+++ b/plugins/check_users.c
@@ -1,33 +1,33 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring check_users plugin 3* Monitoring check_users plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2000-2012 Monitoring Plugins Development Team 6* Copyright (c) 2000-2012 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
10* This file contains the check_users plugin 10* This file contains the check_users plugin
11* 11*
12* This plugin checks the number of users currently logged in on the local 12* This plugin checks the number of users currently logged in on the local
13* system and generates an error if the number exceeds the thresholds 13* system and generates an error if the number exceeds the thresholds
14* specified. 14* specified.
15* 15*
16* 16*
17* This program is free software: you can redistribute it and/or modify 17* This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by 18* it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or 19* the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20* (at your option) any later version.
21* 21*
22* This program is distributed in the hope that it will be useful, 22* This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23* but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25* GNU General Public License for more details.
26* 26*
27* You should have received a copy of the GNU General Public License 27* You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>. 28* along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29*
30* 30*
31*****************************************************************************/ 31*****************************************************************************/
32 32
33const char *progname = "check_users"; 33const char *progname = "check_users";
@@ -48,6 +48,11 @@ const char *email = "devel@monitoring-plugins.org";
48# include "popen.h" 48# include "popen.h"
49#endif 49#endif
50 50
51#ifdef HAVE_LIBSYSTEMD
52#include <systemd/sd-daemon.h>
53#include <systemd/sd-login.h>
54#endif
55
51#define possibly_set(a,b) ((a) == 0 ? (b) : 0) 56#define possibly_set(a,b) ((a) == 0 ? (b) : 0)
52 57
53int process_arguments (int, char **); 58int process_arguments (int, char **);
@@ -85,6 +90,11 @@ main (int argc, char **argv)
85 90
86 users = 0; 91 users = 0;
87 92
93#ifdef HAVE_LIBSYSTEMD
94 if (sd_booted () > 0)
95 users = sd_get_sessions (NULL);
96 else {
97#endif
88#if HAVE_WTSAPI32_H 98#if HAVE_WTSAPI32_H
89 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 99 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
90 0, 1, &wtsinfo, &wtscount)) { 100 0, 1, &wtsinfo, &wtscount)) {
@@ -156,6 +166,9 @@ main (int argc, char **argv)
156 if (spclose (child_process)) 166 if (spclose (child_process))
157 result = possibly_set (result, STATE_UNKNOWN); 167 result = possibly_set (result, STATE_UNKNOWN);
158#endif 168#endif
169#ifdef HAVE_LIBSYSTEMD
170 }
171#endif
159 172
160 /* check the user count against warning and critical thresholds */ 173 /* check the user count against warning and critical thresholds */
161 result = get_status((double)users, thlds); 174 result = get_status((double)users, thlds);
@@ -163,7 +176,7 @@ main (int argc, char **argv)
163 if (result == STATE_UNKNOWN) 176 if (result == STATE_UNKNOWN)
164 printf ("%s\n", _("Unable to read output")); 177 printf ("%s\n", _("Unable to read output"));
165 else { 178 else {
166 printf (_("USERS %s - %d users currently logged in |%s\n"), 179 printf (_("USERS %s - %d users currently logged in |%s\n"),
167 state_text(result), users, 180 state_text(result), users,
168 sperfdata_int("users", users, "", warning_range, 181 sperfdata_int("users", users, "", warning_range,
169 critical_range, TRUE, 0, FALSE, 0)); 182 critical_range, TRUE, 0, FALSE, 0));
diff --git a/plugins/common.h b/plugins/common.h
index 8719b50..6bf4fca 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -174,6 +174,11 @@
174 * 174 *
175 */ 175 */
176 176
177/* MariaDB 10.2 client does not set MYSQL_PORT */
178#ifndef MYSQL_PORT
179# define MYSQL_PORT 3306
180#endif
181
177enum { 182enum {
178 OK = 0, 183 OK = 0,
179 ERROR = -1 184 ERROR = -1
diff --git a/plugins/negate.c b/plugins/negate.c
index b320e35..50f62d3 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -86,11 +86,9 @@ main (int argc, char **argv)
86 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 86 result = cmd_run_array (command_line, &chld_out, &chld_err, 0);
87 } 87 }
88 if (chld_err.lines > 0) { 88 if (chld_err.lines > 0) {
89 printf ("Error output from command:\n");
90 for (i = 0; i < chld_err.lines; i++) { 89 for (i = 0; i < chld_err.lines; i++) {
91 printf ("%s\n", chld_err.line[i]); 90 fprintf (stderr, "%s\n", chld_err.line[i]);
92 } 91 }
93 exit (STATE_WARNING);
94 } 92 }
95 93
96 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
diff --git a/plugins/picohttpparser/Makefile.am b/plugins/picohttpparser/Makefile.am
new file mode 100644
index 0000000..87e0531
--- /dev/null
+++ b/plugins/picohttpparser/Makefile.am
@@ -0,0 +1,3 @@
1noinst_LIBRARIES = libpicohttpparser.a
2
3libpicohttpparser_a_SOURCES = picohttpparser.c picohttpparser.h
diff --git a/plugins/picohttpparser/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c
new file mode 100644
index 0000000..d0bfac6
--- /dev/null
+++ b/plugins/picohttpparser/picohttpparser.c
@@ -0,0 +1,651 @@
1/*
2 * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
3 * Shigeo Mitsunari
4 *
5 * The software is licensed under either the MIT License (below) or the Perl
6 * license.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
26
27#include <assert.h>
28#include <stddef.h>
29#include <string.h>
30#ifdef __SSE4_2__
31#ifdef _MSC_VER
32#include <nmmintrin.h>
33#else
34#include <x86intrin.h>
35#endif
36#endif
37#include "picohttpparser.h"
38
39#if __GNUC__ >= 3
40#define likely(x) __builtin_expect(!!(x), 1)
41#define unlikely(x) __builtin_expect(!!(x), 0)
42#else
43#define likely(x) (x)
44#define unlikely(x) (x)
45#endif
46
47#ifdef _MSC_VER
48#define ALIGNED(n) _declspec(align(n))
49#else
50#define ALIGNED(n) __attribute__((aligned(n)))
51#endif
52
53#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u)
54
55#define CHECK_EOF() \
56 if (buf == buf_end) { \
57 *ret = -2; \
58 return NULL; \
59 }
60
61#define EXPECT_CHAR_NO_CHECK(ch) \
62 if (*buf++ != ch) { \
63 *ret = -1; \
64 return NULL; \
65 }
66
67#define EXPECT_CHAR(ch) \
68 CHECK_EOF(); \
69 EXPECT_CHAR_NO_CHECK(ch);
70
71#define ADVANCE_TOKEN(tok, toklen) \
72 do { \
73 const char *tok_start = buf; \
74 static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \
75 int found2; \
76 buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \
77 if (!found2) { \
78 CHECK_EOF(); \
79 } \
80 while (1) { \
81 if (*buf == ' ') { \
82 break; \
83 } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
84 if ((unsigned char)*buf < '\040' || *buf == '\177') { \
85 *ret = -1; \
86 return NULL; \
87 } \
88 } \
89 ++buf; \
90 CHECK_EOF(); \
91 } \
92 tok = tok_start; \
93 toklen = buf - tok_start; \
94 } while (0)
95
96static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
97 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
98 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
99 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
100 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
104
105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found)
106{
107 *found = 0;
108#if __SSE4_2__
109 if (likely(buf_end - buf >= 16)) {
110 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges);
111
112 size_t left = (buf_end - buf) & ~15;
113 do {
114 __m128i b16 = _mm_loadu_si128((const __m128i *)buf);
115 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
116 if (unlikely(r != 16)) {
117 buf += r;
118 *found = 1;
119 break;
120 }
121 buf += 16;
122 left -= 16;
123 } while (likely(left != 0));
124 }
125#else
126 /* suppress unused parameter warning */
127 (void)buf_end;
128 (void)ranges;
129 (void)ranges_size;
130#endif
131 return buf;
132}
133
134static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret)
135{
136 const char *token_start = buf;
137
138#ifdef __SSE4_2__
139 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */
140 "\012\037" /* allow SP and up to but not including DEL */
141 "\177\177"; /* allow chars w. MSB set */
142 int found;
143 buf = findchar_fast(buf, buf_end, ranges1, 6, &found);
144 if (found)
145 goto FOUND_CTL;
146#else
147 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */
148 while (likely(buf_end - buf >= 8)) {
149#define DOIT() \
150 do { \
151 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
152 goto NonPrintable; \
153 ++buf; \
154 } while (0)
155 DOIT();
156 DOIT();
157 DOIT();
158 DOIT();
159 DOIT();
160 DOIT();
161 DOIT();
162 DOIT();
163#undef DOIT
164 continue;
165 NonPrintable:
166 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
167 goto FOUND_CTL;
168 }
169 ++buf;
170 }
171#endif
172 for (;; ++buf) {
173 CHECK_EOF();
174 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {
175 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
176 goto FOUND_CTL;
177 }
178 }
179 }
180FOUND_CTL:
181 if (likely(*buf == '\015')) {
182 ++buf;
183 EXPECT_CHAR('\012');
184 *token_len = buf - 2 - token_start;
185 } else if (*buf == '\012') {
186 *token_len = buf - token_start;
187 ++buf;
188 } else {
189 *ret = -1;
190 return NULL;
191 }
192 *token = token_start;
193
194 return buf;
195}
196
197static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret)
198{
199 int ret_cnt = 0;
200 buf = last_len < 3 ? buf : buf + last_len - 3;
201
202 while (1) {
203 CHECK_EOF();
204 if (*buf == '\015') {
205 ++buf;
206 CHECK_EOF();
207 EXPECT_CHAR('\012');
208 ++ret_cnt;
209 } else if (*buf == '\012') {
210 ++buf;
211 ++ret_cnt;
212 } else {
213 ++buf;
214 ret_cnt = 0;
215 }
216 if (ret_cnt == 2) {
217 return buf;
218 }
219 }
220
221 *ret = -2;
222 return NULL;
223}
224
225#define PARSE_INT(valp_, mul_) \
226 if (*buf < '0' || '9' < *buf) { \
227 buf++; \
228 *ret = -1; \
229 return NULL; \
230 } \
231 *(valp_) = (mul_) * (*buf++ - '0');
232
233#define PARSE_INT_3(valp_) \
234 do { \
235 int res_ = 0; \
236 PARSE_INT(&res_, 100) \
237 *valp_ = res_; \
238 PARSE_INT(&res_, 10) \
239 *valp_ += res_; \
240 PARSE_INT(&res_, 1) \
241 *valp_ += res_; \
242 } while (0)
243
244/* returned pointer is always within [buf, buf_end), or null */
245static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret)
246{
247 /* we want at least [HTTP/1.<two chars>] to try to parse */
248 if (buf_end - buf < 9) {
249 *ret = -2;
250 return NULL;
251 }
252 EXPECT_CHAR_NO_CHECK('H');
253 EXPECT_CHAR_NO_CHECK('T');
254 EXPECT_CHAR_NO_CHECK('T');
255 EXPECT_CHAR_NO_CHECK('P');
256 EXPECT_CHAR_NO_CHECK('/');
257 PARSE_INT(major_version, 1);
258 if (*major_version == 1) {
259 EXPECT_CHAR_NO_CHECK('.');
260 PARSE_INT(minor_version, 1);
261 } else {
262 *minor_version = 0;
263 }
264 return buf;
265}
266
267static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers,
268 size_t max_headers, int *ret)
269{
270 for (;; ++*num_headers) {
271 CHECK_EOF();
272 if (*buf == '\015') {
273 ++buf;
274 EXPECT_CHAR('\012');
275 break;
276 } else if (*buf == '\012') {
277 ++buf;
278 break;
279 }
280 if (*num_headers == max_headers) {
281 *ret = -1;
282 return NULL;
283 }
284 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) {
285 /* parsing name, but do not discard SP before colon, see
286 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
287 headers[*num_headers].name = buf;
288 static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */
289 "\"\"" /* 0x22 */
290 "()" /* 0x28,0x29 */
291 ",," /* 0x2c */
292 "//" /* 0x2f */
293 ":@" /* 0x3a-0x40 */
294 "[]" /* 0x5b-0x5d */
295 "{\377"; /* 0x7b-0xff */
296 int found;
297 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
298 if (!found) {
299 CHECK_EOF();
300 }
301 while (1) {
302 if (*buf == ':') {
303 break;
304 } else if (!token_char_map[(unsigned char)*buf]) {
305 *ret = -1;
306 return NULL;
307 }
308 ++buf;
309 CHECK_EOF();
310 }
311 if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) {
312 *ret = -1;
313 return NULL;
314 }
315 ++buf;
316 for (;; ++buf) {
317 CHECK_EOF();
318 if (!(*buf == ' ' || *buf == '\t')) {
319 break;
320 }
321 }
322 } else {
323 headers[*num_headers].name = NULL;
324 headers[*num_headers].name_len = 0;
325 }
326 const char *value;
327 size_t value_len;
328 if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) {
329 return NULL;
330 }
331 /* remove trailing SPs and HTABs */
332 const char *value_end = value + value_len;
333 for (; value_end != value; --value_end) {
334 const char c = *(value_end - 1);
335 if (!(c == ' ' || c == '\t')) {
336 break;
337 }
338 }
339 headers[*num_headers].value = value;
340 headers[*num_headers].value_len = value_end - value;
341 }
342 return buf;
343}
344
345static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path,
346 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers,
347 size_t max_headers, int *ret)
348{
349 /* skip first empty line (some clients add CRLF after POST content) */
350 CHECK_EOF();
351 if (*buf == '\015') {
352 ++buf;
353 EXPECT_CHAR('\012');
354 } else if (*buf == '\012') {
355 ++buf;
356 }
357
358 /* parse request line */
359 ADVANCE_TOKEN(*method, *method_len);
360 do {
361 ++buf;
362 } while (*buf == ' ');
363 ADVANCE_TOKEN(*path, *path_len);
364 do {
365 ++buf;
366 } while (*buf == ' ');
367 if (*method_len == 0 || *path_len == 0) {
368 *ret = -1;
369 return NULL;
370 }
371 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
372 return NULL;
373 }
374 if (*buf == '\015') {
375 ++buf;
376 EXPECT_CHAR('\012');
377 } else if (*buf == '\012') {
378 ++buf;
379 } else {
380 *ret = -1;
381 return NULL;
382 }
383
384 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
385}
386
387int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path,
388 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len)
389{
390 const char *buf = buf_start, *buf_end = buf_start + len;
391 size_t max_headers = *num_headers;
392 int r;
393
394 *method = NULL;
395 *method_len = 0;
396 *path = NULL;
397 *path_len = 0;
398 *major_version = -1;
399 *minor_version = -1;
400 *num_headers = 0;
401
402 /* if last_len != 0, check if the request is complete (a fast countermeasure
403 against slowloris */
404 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
405 return r;
406 }
407
408 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers, max_headers,
409 &r)) == NULL) {
410 return r;
411 }
412
413 return (int)(buf - buf_start);
414}
415
416static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status, const char **msg,
417 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret)
418{
419 /* parse "HTTP/1.x" */
420 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
421 return NULL;
422 }
423 /* skip space */
424 if (*buf != ' ') {
425 *ret = -1;
426 return NULL;
427 }
428 do {
429 ++buf;
430 } while (*buf == ' ');
431 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */
432 if (buf_end - buf < 4) {
433 *ret = -2;
434 return NULL;
435 }
436 PARSE_INT_3(status);
437
438 /* get message including preceding space */
439 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) {
440 return NULL;
441 }
442 if (*msg_len == 0) {
443 /* ok */
444 } else if (**msg == ' ') {
445 /* remove preceding space */
446 do {
447 ++*msg;
448 --*msg_len;
449 } while (**msg == ' ');
450 } else {
451 /* garbage found after status code */
452 *ret = -1;
453 return NULL;
454 }
455
456 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
457}
458
459int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len,
460 struct phr_header *headers, size_t *num_headers, size_t last_len)
461{
462 const char *buf = buf_start, *buf_end = buf + len;
463 size_t max_headers = *num_headers;
464 int r;
465
466 *major_version = -1;
467 *minor_version = -1;
468 *status = 0;
469 *msg = NULL;
470 *msg_len = 0;
471 *num_headers = 0;
472
473 /* if last_len != 0, check if the response is complete (a fast countermeasure
474 against slowloris */
475 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
476 return r;
477 }
478
479 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) {
480 return r;
481 }
482
483 return (int)(buf - buf_start);
484}
485
486int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len)
487{
488 const char *buf = buf_start, *buf_end = buf + len;
489 size_t max_headers = *num_headers;
490 int r;
491
492 *num_headers = 0;
493
494 /* if last_len != 0, check if the response is complete (a fast countermeasure
495 against slowloris */
496 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
497 return r;
498 }
499
500 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) {
501 return r;
502 }
503
504 return (int)(buf - buf_start);
505}
506
507enum {
508 CHUNKED_IN_CHUNK_SIZE,
509 CHUNKED_IN_CHUNK_EXT,
510 CHUNKED_IN_CHUNK_DATA,
511 CHUNKED_IN_CHUNK_CRLF,
512 CHUNKED_IN_TRAILERS_LINE_HEAD,
513 CHUNKED_IN_TRAILERS_LINE_MIDDLE
514};
515
516static int decode_hex(int ch)
517{
518 if ('0' <= ch && ch <= '9') {
519 return ch - '0';
520 } else if ('A' <= ch && ch <= 'F') {
521 return ch - 'A' + 0xa;
522 } else if ('a' <= ch && ch <= 'f') {
523 return ch - 'a' + 0xa;
524 } else {
525 return -1;
526 }
527}
528
529ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz)
530{
531 size_t dst = 0, src = 0, bufsz = *_bufsz;
532 ssize_t ret = -2; /* incomplete */
533
534 while (1) {
535 switch (decoder->_state) {
536 case CHUNKED_IN_CHUNK_SIZE:
537 for (;; ++src) {
538 int v;
539 if (src == bufsz)
540 goto Exit;
541 if ((v = decode_hex(buf[src])) == -1) {
542 if (decoder->_hex_count == 0) {
543 ret = -1;
544 goto Exit;
545 }
546 break;
547 }
548 if (decoder->_hex_count == sizeof(size_t) * 2) {
549 ret = -1;
550 goto Exit;
551 }
552 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
553 ++decoder->_hex_count;
554 }
555 decoder->_hex_count = 0;
556 decoder->_state = CHUNKED_IN_CHUNK_EXT;
557 /* fallthru */
558 case CHUNKED_IN_CHUNK_EXT:
559 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
560 for (;; ++src) {
561 if (src == bufsz)
562 goto Exit;
563 if (buf[src] == '\012')
564 break;
565 }
566 ++src;
567 if (decoder->bytes_left_in_chunk == 0) {
568 if (decoder->consume_trailer) {
569 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
570 break;
571 } else {
572 goto Complete;
573 }
574 }
575 decoder->_state = CHUNKED_IN_CHUNK_DATA;
576 /* fallthru */
577 case CHUNKED_IN_CHUNK_DATA: {
578 size_t avail = bufsz - src;
579 if (avail < decoder->bytes_left_in_chunk) {
580 if (dst != src)
581 memmove(buf + dst, buf + src, avail);
582 src += avail;
583 dst += avail;
584 decoder->bytes_left_in_chunk -= avail;
585 goto Exit;
586 }
587 if (dst != src)
588 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
589 src += decoder->bytes_left_in_chunk;
590 dst += decoder->bytes_left_in_chunk;
591 decoder->bytes_left_in_chunk = 0;
592 decoder->_state = CHUNKED_IN_CHUNK_CRLF;
593 }
594 /* fallthru */
595 case CHUNKED_IN_CHUNK_CRLF:
596 for (;; ++src) {
597 if (src == bufsz)
598 goto Exit;
599 if (buf[src] != '\015')
600 break;
601 }
602 if (buf[src] != '\012') {
603 ret = -1;
604 goto Exit;
605 }
606 ++src;
607 decoder->_state = CHUNKED_IN_CHUNK_SIZE;
608 break;
609 case CHUNKED_IN_TRAILERS_LINE_HEAD:
610 for (;; ++src) {
611 if (src == bufsz)
612 goto Exit;
613 if (buf[src] != '\015')
614 break;
615 }
616 if (buf[src++] == '\012')
617 goto Complete;
618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
619 /* fallthru */
620 case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
621 for (;; ++src) {
622 if (src == bufsz)
623 goto Exit;
624 if (buf[src] == '\012')
625 break;
626 }
627 ++src;
628 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
629 break;
630 default:
631 assert(!"decoder is corrupt");
632 }
633 }
634
635Complete:
636 ret = bufsz - src;
637Exit:
638 if (dst != src)
639 memmove(buf + dst, buf + src, bufsz - src);
640 *_bufsz = dst;
641 return ret;
642}
643
644int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder)
645{
646 return decoder->_state == CHUNKED_IN_CHUNK_DATA;
647}
648
649#undef CHECK_EOF
650#undef EXPECT_CHAR
651#undef ADVANCE_TOKEN
diff --git a/plugins/picohttpparser/picohttpparser.h b/plugins/picohttpparser/picohttpparser.h
new file mode 100644
index 0000000..8f13b36
--- /dev/null
+++ b/plugins/picohttpparser/picohttpparser.h
@@ -0,0 +1,87 @@
1/*
2 * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
3 * Shigeo Mitsunari
4 *
5 * The software is licensed under either the MIT License (below) or the Perl
6 * license.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
26
27#ifndef picohttpparser_h
28#define picohttpparser_h
29
30#include <sys/types.h>
31
32#ifdef _MSC_VER
33#define ssize_t intptr_t
34#endif
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40/* contains name and value of a header (name == NULL if is a continuing line
41 * of a multiline header */
42struct phr_header {
43 const char *name;
44 size_t name_len;
45 const char *value;
46 size_t value_len;
47};
48
49/* returns number of bytes consumed if successful, -2 if request is partial,
50 * -1 if failed */
51int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len,
52 int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len);
53
54/* ditto */
55int phr_parse_response(const char *_buf, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len,
56 struct phr_header *headers, size_t *num_headers, size_t last_len);
57
58/* ditto */
59int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len);
60
61/* should be zero-filled before start */
62struct phr_chunked_decoder {
63 size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
64 char consume_trailer; /* if trailing headers should be consumed */
65 char _hex_count;
66 char _state;
67};
68
69/* the function rewrites the buffer given as (buf, bufsz) removing the chunked-
70 * encoding headers. When the function returns without an error, bufsz is
71 * updated to the length of the decoded data available. Applications should
72 * repeatedly call the function while it returns -2 (incomplete) every time
73 * supplying newly arrived data. If the end of the chunked-encoded data is
74 * found, the function returns a non-negative number indicating the number of
75 * octets left undecoded at the tail of the supplied buffer. Returns -1 on
76 * error.
77 */
78ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *bufsz);
79
80/* returns if the chunked decoder is in middle of chunked data */
81int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder);
82
83#ifdef __cplusplus
84}
85#endif
86
87#endif
diff --git a/plugins/popen.c b/plugins/popen.c
index 592263f..b395f14 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -14,7 +14,7 @@
14* FILE * spopen(const char *); 14* FILE * spopen(const char *);
15* int spclose(FILE *); 15* int spclose(FILE *);
16* 16*
17* Code taken with liitle modification from "Advanced Programming for the Unix 17* Code taken with little modification from "Advanced Programming for the Unix
18* Environment" by W. Richard Stevens 18* Environment" by W. Richard Stevens
19* 19*
20* This is considered safe in that no shell is spawned, and the environment 20* This is considered safe in that no shell is spawned, and the environment
@@ -38,10 +38,11 @@
38* 38*
39*****************************************************************************/ 39*****************************************************************************/
40 40
41#include "common.h" 41#include "./common.h"
42#include "./utils.h"
43#include "../lib/maxfd.h"
42 44
43/* extern so plugin has pid to kill exec'd process on timeouts */ 45/* extern so plugin has pid to kill exec'd process on timeouts */
44extern int timeout_interval;
45extern pid_t *childpid; 46extern pid_t *childpid;
46extern int *child_stderr_array; 47extern int *child_stderr_array;
47extern FILE *child_process; 48extern FILE *child_process;
@@ -76,18 +77,9 @@ RETSIGTYPE popen_timeout_alarm_handler (int);
76#define SIG_ERR ((Sigfunc *)-1) 77#define SIG_ERR ((Sigfunc *)-1)
77#endif 78#endif
78 79
79#define min(a,b) ((a) < (b) ? (a) : (b))
80#define max(a,b) ((a) > (b) ? (a) : (b))
81int open_max (void); /* {Prog openmax} */
82static void err_sys (const char *, ...) __attribute__((noreturn,format(printf, 1, 2)));
83char *rtrim (char *, const char *);
84 80
85char *pname = NULL; /* caller can set this from argv[0] */ 81char *pname = NULL; /* caller can set this from argv[0] */
86 82
87/*int *childerr = NULL;*//* ptr to array allocated at run-time */
88/*extern pid_t *childpid = NULL; *//* ptr to array allocated at run-time */
89static int maxfd; /* from our open_max(), {Prog openmax} */
90
91#ifdef REDHAT_SPOPEN_ERROR 83#ifdef REDHAT_SPOPEN_ERROR
92static volatile int childtermd = 0; 84static volatile int childtermd = 0;
93#endif 85#endif
@@ -186,14 +178,14 @@ spopen (const char *cmdstring)
186 } 178 }
187 argv[i] = NULL; 179 argv[i] = NULL;
188 180
181 long maxfd = mp_open_max();
182
189 if (childpid == NULL) { /* first time through */ 183 if (childpid == NULL) { /* first time through */
190 maxfd = open_max (); /* allocate zeroed out array for child pids */
191 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL) 184 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL)
192 return (NULL); 185 return (NULL);
193 } 186 }
194 187
195 if (child_stderr_array == NULL) { /* first time through */ 188 if (child_stderr_array == NULL) { /* first time through */
196 maxfd = open_max (); /* allocate zeroed out array for child pids */
197 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL) 189 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL)
198 return (NULL); 190 return (NULL);
199 } 191 }
@@ -273,15 +265,6 @@ spclose (FILE * fp)
273 return (1); 265 return (1);
274} 266}
275 267
276#ifdef OPEN_MAX
277static int openmax = OPEN_MAX;
278#else
279static int openmax = 0;
280#endif
281
282#define OPEN_MAX_GUESS 256 /* if OPEN_MAX is indeterminate */
283 /* no guarantee this is adequate */
284
285#ifdef REDHAT_SPOPEN_ERROR 268#ifdef REDHAT_SPOPEN_ERROR
286RETSIGTYPE 269RETSIGTYPE
287popen_sigchld_handler (int signo) 270popen_sigchld_handler (int signo)
@@ -309,63 +292,3 @@ popen_timeout_alarm_handler (int signo)
309 exit (STATE_CRITICAL); 292 exit (STATE_CRITICAL);
310 } 293 }
311} 294}
312
313
314int
315open_max (void)
316{
317 if (openmax == 0) { /* first time through */
318 errno = 0;
319 if ((openmax = sysconf (_SC_OPEN_MAX)) < 0) {
320 if (errno == 0)
321 openmax = OPEN_MAX_GUESS; /* it's indeterminate */
322 else
323 err_sys (_("sysconf error for _SC_OPEN_MAX"));
324 }
325 }
326 return (openmax);
327}
328
329
330/* Fatal error related to a system call.
331 * Print a message and die. */
332
333#define MAXLINE 2048
334static void
335err_sys (const char *fmt, ...)
336{
337 int errnoflag = 1;
338 int errno_save;
339 char buf[MAXLINE];
340
341 va_list ap;
342
343 va_start (ap, fmt);
344 /* err_doit (1, fmt, ap); */
345 errno_save = errno; /* value caller might want printed */
346 vsprintf (buf, fmt, ap);
347 if (errnoflag)
348 sprintf (buf + strlen (buf), ": %s", strerror (errno_save));
349 strcat (buf, "\n");
350 fflush (stdout); /* in case stdout and stderr are the same */
351 fputs (buf, stderr);
352 fflush (NULL); /* flushes all stdio output streams */
353 va_end (ap);
354 exit (1);
355}
356
357char *
358rtrim (char *str, const char *tok)
359{
360 int i = 0;
361 int j = sizeof (str);
362
363 while (str != NULL && i < j) {
364 if (*(str + i) == *tok) {
365 sprintf (str + i, "%s", "\0");
366 return str;
367 }
368 i++;
369 }
370 return str;
371}
diff --git a/plugins/popen.h b/plugins/popen.h
index fc7e78e..a5dd8fa 100644
--- a/plugins/popen.h
+++ b/plugins/popen.h
@@ -7,7 +7,6 @@ FILE *spopen (const char *);
7int spclose (FILE *); 7int spclose (FILE *);
8RETSIGTYPE popen_timeout_alarm_handler (int); 8RETSIGTYPE popen_timeout_alarm_handler (int);
9 9
10extern unsigned int timeout_interval;
11pid_t *childpid=NULL; 10pid_t *childpid=NULL;
12int *child_stderr_array=NULL; 11int *child_stderr_array=NULL;
13FILE *child_process=NULL; 12FILE *child_process=NULL;
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index 1a7c904..bc0a497 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -44,6 +44,8 @@
44# include <sys/wait.h> 44# include <sys/wait.h>
45#endif 45#endif
46 46
47#include "./utils.h"
48
47/** macros **/ 49/** macros **/
48#ifndef WEXITSTATUS 50#ifndef WEXITSTATUS
49# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 51# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
@@ -67,19 +69,6 @@
67 * occur in any number of threads simultaneously. */ 69 * occur in any number of threads simultaneously. */
68static pid_t *np_pids = NULL; 70static pid_t *np_pids = NULL;
69 71
70/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
71 * If that fails and the macro isn't defined, we fall back to an educated
72 * guess. There's no guarantee that our guess is adequate and the program
73 * will die with SIGSEGV if it isn't and the upper boundary is breached. */
74#ifdef _SC_OPEN_MAX
75static long maxfd = 0;
76#elif defined(OPEN_MAX)
77# define maxfd OPEN_MAX
78#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
79# define maxfd 256
80#endif
81
82
83/** prototypes **/ 72/** prototypes **/
84static int np_runcmd_open(const char *, int *, int *) 73static int np_runcmd_open(const char *, int *, int *)
85 __attribute__((__nonnull__(1, 2, 3))); 74 __attribute__((__nonnull__(1, 2, 3)));
@@ -99,14 +88,7 @@ extern void die (int, const char *, ...)
99 * through this api and thus achieve async-safeness throughout the api */ 88 * through this api and thus achieve async-safeness throughout the api */
100void np_runcmd_init(void) 89void np_runcmd_init(void)
101{ 90{
102#ifndef maxfd 91 long maxfd = mp_open_max();
103 if(!maxfd && (maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
104 /* possibly log or emit a warning here, since there's no
105 * guarantee that our guess at maxfd will be adequate */
106 maxfd = 256;
107 }
108#endif
109
110 if(!np_pids) np_pids = calloc(maxfd, sizeof(pid_t)); 92 if(!np_pids) np_pids = calloc(maxfd, sizeof(pid_t));
111} 93}
112 94
@@ -133,10 +115,6 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
133 env[0] = strdup("LC_ALL=C"); 115 env[0] = strdup("LC_ALL=C");
134 env[1] = '\0'; 116 env[1] = '\0';
135 117
136 /* if no command was passed, return with no error */
137 if (cmdstring == NULL)
138 return -1;
139
140 /* make copy of command string so strtok() doesn't silently modify it */ 118 /* make copy of command string so strtok() doesn't silently modify it */
141 /* (the calling program may want to access it later) */ 119 /* (the calling program may want to access it later) */
142 cmdlen = strlen(cmdstring); 120 cmdlen = strlen(cmdstring);
@@ -213,6 +191,7 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
213 /* close all descriptors in np_pids[] 191 /* close all descriptors in np_pids[]
214 * This is executed in a separate address space (pure child), 192 * This is executed in a separate address space (pure child),
215 * so we don't have to worry about async safety */ 193 * so we don't have to worry about async safety */
194 long maxfd = mp_open_max();
216 for (i = 0; i < maxfd; i++) 195 for (i = 0; i < maxfd; i++)
217 if(np_pids[i] > 0) 196 if(np_pids[i] > 0)
218 close (i); 197 close (i);
@@ -222,7 +201,7 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
222 } 201 }
223 202
224 /* parent picks up execution here */ 203 /* parent picks up execution here */
225 /* close childs descriptors in our address space */ 204 /* close children descriptors in our address space */
226 close(pfd[1]); 205 close(pfd[1]);
227 close(pfderr[1]); 206 close(pfderr[1]);
228 207
@@ -240,6 +219,7 @@ np_runcmd_close(int fd)
240 pid_t pid; 219 pid_t pid;
241 220
242 /* make sure this fd was opened by popen() */ 221 /* make sure this fd was opened by popen() */
222 long maxfd = mp_open_max();
243 if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) 223 if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0)
244 return -1; 224 return -1;
245 225
@@ -263,6 +243,7 @@ runcmd_timeout_alarm_handler (int signo)
263 if (signo == SIGALRM) 243 if (signo == SIGALRM)
264 puts(_("CRITICAL - Plugin timed out while executing system call")); 244 puts(_("CRITICAL - Plugin timed out while executing system call"));
265 245
246 long maxfd = mp_open_max();
266 if(np_pids) for(i = 0; i < maxfd; i++) { 247 if(np_pids) for(i = 0; i < maxfd; i++) {
267 if(np_pids[i] != 0) kill(np_pids[i], SIGKILL); 248 if(np_pids[i] != 0) kill(np_pids[i], SIGKILL);
268 } 249 }
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index e38947e..6bc0ba8 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -1,29 +1,29 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2*
3* Monitoring Plugins SSL utilities 3* Monitoring Plugins SSL utilities
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2005-2010 Monitoring Plugins Development Team 6* Copyright (c) 2005-2010 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
10* This file contains common functions for plugins that require SSL. 10* This file contains common functions for plugins that require SSL.
11* 11*
12* 12*
13* This program is free software: you can redistribute it and/or modify 13* This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14* it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15* the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16* (at your option) any later version.
17* 17*
18* This program is distributed in the hope that it will be useful, 18* This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19* but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21* GNU General Public License for more details.
22* 22*
23* You should have received a copy of the GNU General Public License 23* You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24* along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25*
26* 26*
27*****************************************************************************/ 27*****************************************************************************/
28 28
29#define MAX_CN_LENGTH 256 29#define MAX_CN_LENGTH 256
@@ -31,9 +31,8 @@
31#include "netutils.h" 31#include "netutils.h"
32 32
33#ifdef HAVE_SSL 33#ifdef HAVE_SSL
34static SSL_CTX *c=NULL; 34static SSL_CTX *ctx=NULL;
35static SSL *s=NULL; 35static SSL *s=NULL;
36static int initialized=0;
37 36
38int np_net_ssl_init(int sd) { 37int np_net_ssl_init(int sd) {
39 return np_net_ssl_init_with_hostname(sd, NULL); 38 return np_net_ssl_init_with_hostname(sd, NULL);
@@ -48,24 +47,24 @@ int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int versi
48} 47}
49 48
50int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey) { 49int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey) {
51 const SSL_METHOD *method = NULL;
52 long options = 0; 50 long options = 0;
53 51
52 if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
53 printf("%s\n", _("CRITICAL - Cannot create SSL context."));
54 return STATE_CRITICAL;
55 }
56
54 switch (version) { 57 switch (version) {
55 case MP_SSLv2: /* SSLv2 protocol */ 58 case MP_SSLv2: /* SSLv2 protocol */
56#if defined(USE_GNUTLS) || defined(OPENSSL_NO_SSL2)
57 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library.")); 59 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library."));
58 return STATE_UNKNOWN; 60 return STATE_UNKNOWN;
59#else
60 method = SSLv2_client_method();
61 break;
62#endif
63 case MP_SSLv3: /* SSLv3 protocol */ 61 case MP_SSLv3: /* SSLv3 protocol */
64#if defined(OPENSSL_NO_SSL3) 62#if defined(OPENSSL_NO_SSL3)
65 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library.")); 63 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library."));
66 return STATE_UNKNOWN; 64 return STATE_UNKNOWN;
67#else 65#else
68 method = SSLv3_client_method(); 66 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
67 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
69 break; 68 break;
70#endif 69#endif
71 case MP_TLSv1: /* TLSv1 protocol */ 70 case MP_TLSv1: /* TLSv1 protocol */
@@ -73,7 +72,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
73 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library.")); 72 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library."));
74 return STATE_UNKNOWN; 73 return STATE_UNKNOWN;
75#else 74#else
76 method = TLSv1_client_method(); 75 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
76 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
77 break; 77 break;
78#endif 78#endif
79 case MP_TLSv1_1: /* TLSv1.1 protocol */ 79 case MP_TLSv1_1: /* TLSv1.1 protocol */
@@ -81,7 +81,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
81 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library.")); 81 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
82 return STATE_UNKNOWN; 82 return STATE_UNKNOWN;
83#else 83#else
84 method = TLSv1_1_client_method(); 84 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
85 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
85 break; 86 break;
86#endif 87#endif
87 case MP_TLSv1_2: /* TLSv1.2 protocol */ 88 case MP_TLSv1_2: /* TLSv1.2 protocol */
@@ -89,7 +90,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
89 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library.")); 90 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
90 return STATE_UNKNOWN; 91 return STATE_UNKNOWN;
91#else 92#else
92 method = TLSv1_2_client_method(); 93 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
94 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
93 break; 95 break;
94#endif 96#endif
95 case MP_TLSv1_2_OR_NEWER: 97 case MP_TLSv1_2_OR_NEWER:
@@ -97,47 +99,43 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
97 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library.")); 99 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library."));
98 return STATE_UNKNOWN; 100 return STATE_UNKNOWN;
99#else 101#else
100 options |= SSL_OP_NO_TLSv1_1; 102 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
103 break;
101#endif 104#endif
102 /* FALLTHROUGH */
103 case MP_TLSv1_1_OR_NEWER: 105 case MP_TLSv1_1_OR_NEWER:
104#if !defined(SSL_OP_NO_TLSv1) 106#if !defined(SSL_OP_NO_TLSv1)
105 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library.")); 107 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library."));
106 return STATE_UNKNOWN; 108 return STATE_UNKNOWN;
107#else 109#else
108 options |= SSL_OP_NO_TLSv1; 110 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
111 break;
109#endif 112#endif
110 /* FALLTHROUGH */
111 case MP_TLSv1_OR_NEWER: 113 case MP_TLSv1_OR_NEWER:
112#if defined(SSL_OP_NO_SSLv3) 114#if defined(SSL_OP_NO_SSLv3)
113 options |= SSL_OP_NO_SSLv3; 115 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
116 break;
114#endif 117#endif
115 /* FALLTHROUGH */
116 case MP_SSLv3_OR_NEWER: 118 case MP_SSLv3_OR_NEWER:
117#if defined(SSL_OP_NO_SSLv2) 119#if defined(SSL_OP_NO_SSLv2)
118 options |= SSL_OP_NO_SSLv2; 120 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
121 break;
119#endif 122#endif
120 case MP_SSLv2_OR_NEWER:
121 /* FALLTHROUGH */
122 default: /* Default to auto negotiation */
123 method = SSLv23_client_method();
124 }
125 if (!initialized) {
126 /* Initialize SSL context */
127 SSLeay_add_ssl_algorithms();
128 SSL_load_error_strings();
129 OpenSSL_add_all_algorithms();
130 initialized = 1;
131 }
132 if ((c = SSL_CTX_new(method)) == NULL) {
133 printf("%s\n", _("CRITICAL - Cannot create SSL context."));
134 return STATE_CRITICAL;
135 } 123 }
124
136 if (cert && privkey) { 125 if (cert && privkey) {
137 SSL_CTX_use_certificate_file(c, cert, SSL_FILETYPE_PEM);
138 SSL_CTX_use_PrivateKey_file(c, privkey, SSL_FILETYPE_PEM);
139#ifdef USE_OPENSSL 126#ifdef USE_OPENSSL
140 if (!SSL_CTX_check_private_key(c)) { 127 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
128#elif USE_GNUTLS
129 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) {
130#else
131#error Unported for unknown SSL library
132#endif
133 printf ("%s\n", _("CRITICAL - Unable to open certificate chain file!\n"));
134 return STATE_CRITICAL;
135 }
136 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM);
137#ifdef USE_OPENSSL
138 if (!SSL_CTX_check_private_key(ctx)) {
141 printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n")); 139 printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
142 return STATE_CRITICAL; 140 return STATE_CRITICAL;
143 } 141 }
@@ -146,9 +144,9 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
146#ifdef SSL_OP_NO_TICKET 144#ifdef SSL_OP_NO_TICKET
147 options |= SSL_OP_NO_TICKET; 145 options |= SSL_OP_NO_TICKET;
148#endif 146#endif
149 SSL_CTX_set_options(c, options); 147 SSL_CTX_set_options(ctx, options);
150 SSL_CTX_set_mode(c, SSL_MODE_AUTO_RETRY); 148 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
151 if ((s = SSL_new(c)) != NULL) { 149 if ((s = SSL_new(ctx)) != NULL) {
152#ifdef SSL_set_tlsext_host_name 150#ifdef SSL_set_tlsext_host_name
153 if (host_name != NULL) 151 if (host_name != NULL)
154 SSL_set_tlsext_host_name(s, host_name); 152 SSL_set_tlsext_host_name(s, host_name);
@@ -175,9 +173,9 @@ void np_net_ssl_cleanup() {
175#endif 173#endif
176 SSL_shutdown(s); 174 SSL_shutdown(s);
177 SSL_free(s); 175 SSL_free(s);
178 if (c) { 176 if (ctx) {
179 SSL_CTX_free(c); 177 SSL_CTX_free(ctx);
180 c=NULL; 178 ctx=NULL;
181 } 179 }
182 s=NULL; 180 s=NULL;
183 } 181 }
@@ -191,14 +189,13 @@ int np_net_ssl_read(void *buf, int num) {
191 return SSL_read(s, buf, num); 189 return SSL_read(s, buf, num);
192} 190}
193 191
194int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){ 192int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit){
195# ifdef USE_OPENSSL 193# ifdef USE_OPENSSL
196 X509 *certificate=NULL;
197 X509_NAME *subj=NULL; 194 X509_NAME *subj=NULL;
198 char timestamp[50] = ""; 195 char timestamp[50] = "";
199 char cn[MAX_CN_LENGTH]= ""; 196 char cn[MAX_CN_LENGTH]= "";
200 char *tz; 197 char *tz;
201 198
202 int cnlen =-1; 199 int cnlen =-1;
203 int status=STATE_UNKNOWN; 200 int status=STATE_UNKNOWN;
204 201
@@ -210,7 +207,6 @@ int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
210 int time_remaining; 207 int time_remaining;
211 time_t tm_t; 208 time_t tm_t;
212 209
213 certificate=SSL_get_peer_certificate(s);
214 if (!certificate) { 210 if (!certificate) {
215 printf("%s\n",_("CRITICAL - Cannot retrieve server certificate.")); 211 printf("%s\n",_("CRITICAL - Cannot retrieve server certificate."));
216 return STATE_CRITICAL; 212 return STATE_CRITICAL;
@@ -319,4 +315,16 @@ int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
319# endif /* USE_OPENSSL */ 315# endif /* USE_OPENSSL */
320} 316}
321 317
318int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
319# ifdef USE_OPENSSL
320 X509 *certificate = NULL;
321 certificate=SSL_get_peer_certificate(s);
322 return(np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit));
323# else /* ifndef USE_OPENSSL */
324 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
325 return STATE_WARNING;
326# endif /* USE_OPENSSL */
327}
328
329
322#endif /* HAVE_SSL */ 330#endif /* HAVE_SSL */
diff --git a/plugins/t/NPTest.cache.travis b/plugins/t/NPTest.cache.travis
deleted file mode 100644
index e9705f3..0000000
--- a/plugins/t/NPTest.cache.travis
+++ /dev/null
@@ -1,62 +0,0 @@
1{
2 'MYSQL_LOGIN_DETAILS' => '-u root -d test',
3 'NP_ALLOW_SUDO' => 'yes',
4 'NP_DNS_SERVER' => '8.8.8.8',
5 'NP_GOOD_NTP_SERVICE' => '',
6 'NP_HOSTNAME_INVALID' => 'nosuchhost',
7 'NP_HOSTNAME_VALID' => 'monitoring-plugins.org',
8 'NP_HOSTNAME_VALID_IP' => '130.133.8.40',
9 'NP_HOSTNAME_VALID_CIDR' => '130.133.8.41/30',
10 'NP_HOSTNAME_INVALID_CIDR' => '130.133.8.39/30',
11 'NP_HOSTNAME_VALID_REVERSE' => 'orwell.monitoring-plugins.org.',
12 'NP_HOST_DHCP_RESPONSIVE' => '',
13 'NP_HOST_NONRESPONSIVE' => '10.0.0.1',
14 'NP_HOST_RESPONSIVE' => 'localhost',
15 'NP_HOST_SMB' => '',
16 'NP_HOST_SNMP' => 'localhost',
17 'NP_HOST_TCP_FTP' => '',
18 'NP_HOST_TCP_HPJD' => '',
19 'NP_HOST_HPJD_PORT_INVALID' => '161',
20 'NP_HOST_HPJD_PORT_VALID' => '',
21 'NP_HOST_TCP_HTTP' => 'localhost',
22 'NP_HOST_TCP_HTTP2' => 'test.monitoring-plugins.org',
23 'NP_HOST_TCP_IMAP' => 'imap.web.de',
24 'NP_HOST_TCP_LDAP' => 'localhost',
25 'NP_HOST_TCP_POP' => 'pop.web.de',
26 'NP_HOST_TCP_SMTP' => 'localhost',
27 'NP_HOST_TCP_SMTP_NOTLS' => '',
28 'NP_HOST_TCP_SMTP_TLS' => '',
29 'NP_INTERNET_ACCESS' => 'yes',
30 'NP_LDAP_BASE_DN' => 'cn=admin,dc=nodomain',
31 'NP_MOUNTPOINT2_VALID' => '/media/ramdisk',
32 'NP_MOUNTPOINT_VALID' => '/',
33 'NP_MYSQL_SERVER' => 'localhost',
34 'NP_HOST_UDP_TIME' => 'localhost',
35 'NP_MYSQL_SOCKET' => '/var/run/mysqld/mysqld.sock',
36 'NP_MYSQL_WITH_SLAVE' => '',
37 'NP_MYSQL_WITH_SLAVE_LOGIN' => '',
38 'NP_NO_NTP_SERVICE' => 'localhost',
39 'NP_SMB_SHARE' => '',
40 'NP_SMB_SHARE_DENY' => '',
41 'NP_SMB_SHARE_SPC' => '',
42 'NP_SMB_VALID_USER' => '',
43 'NP_SMB_VALID_USER_PASS' => '',
44 'NP_SNMP_COMMUNITY' => 'public',
45 'NP_SSH_CONFIGFILE' => '~/.ssh/config',
46 'NP_SSH_HOST' => 'localhost',
47 'NP_SSH_IDENTITY' => '~/.ssh/id_dsa',
48 'NP_HOST_TCP_JABBER' => 'jabber.org',
49 'host_nonresponsive' => '10.0.0.1',
50 'host_responsive' => 'localhost',
51 'host_snmp' => '',
52 'host_tcp_ftp' => '',
53 'host_tcp_http' => 'localhost',
54 'host_tcp_imap' => 'imap.nierlein.de',
55 'host_tcp_smtp' => 'localhost',
56 'hostname_invalid' => 'nosuchhost',
57 'snmp_community' => '',
58 'user_snmp' => '',
59 'host_udp_time' => 'none',
60 'host_tls_http' => 'localhost',
61 'host_tls_cert' => 'localhost',
62}
diff --git a/plugins/t/check_by_ssh.t b/plugins/t/check_by_ssh.t
index 4797390..b6479f1 100644
--- a/plugins/t/check_by_ssh.t
+++ b/plugins/t/check_by_ssh.t
@@ -9,17 +9,9 @@ use Test::More;
9use NPTest; 9use NPTest;
10 10
11# Required parameters 11# Required parameters
12my $ssh_service = getTestParameter( "NP_SSH_HOST", 12my $ssh_service = getTestParameter("NP_SSH_HOST", "A host providing SSH service", "localhost");
13 "A host providing SSH service", 13my $ssh_key = getTestParameter("NP_SSH_IDENTITY", "A key allowing access to NP_SSH_HOST", "~/.ssh/id_dsa");
14 "localhost"); 14my $ssh_conf = getTestParameter( "NP_SSH_CONFIGFILE", "A config file with ssh settings", "~/.ssh/config");
15
16my $ssh_key = getTestParameter( "NP_SSH_IDENTITY",
17 "A key allowing access to NP_SSH_HOST",
18 "~/.ssh/id_dsa");
19
20my $ssh_conf = getTestParameter( "NP_SSH_CONFIGFILE",
21 "A config file with ssh settings",
22 "~/.ssh/config");
23 15
24 16
25plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key); 17plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key);
@@ -27,19 +19,19 @@ plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_servic
27plan tests => 42; 19plan tests => 42;
28 20
29# Some random check strings/response 21# Some random check strings/response
30my @responce = ('OK: Everything is fine', 22my @response = ('OK: Everything is fine',
31 'WARNING: Hey, pick me, pick me', 23 'WARNING: Hey, pick me, pick me',
32 'CRITICAL: Shit happens', 24 'CRITICAL: Shit happens',
33 'UNKNOWN: What can I do for ya', 25 'UNKNOWN: What can I do for ya',
34 'WOOPS: What did I smoke', 26 'WOOPS: What did I smoke',
35); 27);
36my @responce_re; 28my @response_re;
37my @check; 29my @check;
38for (@responce) { 30for (@response) {
39 push(@check, "echo $_"); 31 push(@check, "echo $_");
40 my $re_str = $_; 32 my $re_str = $_;
41 $re_str =~ s{(.)} { "\Q$1" }ge; 33 $re_str =~ s{(.)} { "\Q$1" }ge;
42 push(@responce_re, $re_str); 34 push(@response_re, $re_str);
43} 35}
44 36
45my $result; 37my $result;
@@ -55,7 +47,7 @@ for (my $i=0; $i<4; $i++) {
55 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'" 47 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'"
56 ); 48 );
57 cmp_ok($result->return_code, '==', $i, "Exit with return code $i"); 49 cmp_ok($result->return_code, '==', $i, "Exit with return code $i");
58 is($result->output, $responce[$i], "Status text is correct for check $i"); 50 is($result->output, $response[$i], "Status text is correct for check $i");
59} 51}
60 52
61$result = NPTest->testCmd( 53$result = NPTest->testCmd(
@@ -92,7 +84,7 @@ $result = NPTest->testCmd(
92 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'" 84 "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'"
93 ); 85 );
94cmp_ok($result->return_code, '==', 8, "Exit with return code 8 (out of bounds)"); 86cmp_ok($result->return_code, '==', 8, "Exit with return code 8 (out of bounds)");
95is($result->output, $responce[4], "Return proper status text even with unknown status codes"); 87is($result->output, $response[4], "Return proper status text even with unknown status codes");
96 88
97$result = NPTest->testCmd( 89$result = NPTest->testCmd(
98 "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'" 90 "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'"
@@ -116,7 +108,7 @@ my %linemap = (
116foreach my $line (0, 2, 4, 6) { 108foreach my $line (0, 2, 4, 6) {
117 my $code = $linemap{$line}; 109 my $code = $linemap{$line};
118 my $statline = $line+1; 110 my $statline = $line+1;
119 is($lines[$line], "$responce[$code]", "multiple checks status text is correct for line $line"); 111 is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line");
120 is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line"); 112 is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line");
121} 113}
122 114
@@ -132,7 +124,7 @@ close(PASV) or die("Unable to close '/tmp/check_by_ssh.$$': $!");
132cmp_ok(scalar(@pasv), '==', 1, 'One passive result for one check performed'); 124cmp_ok(scalar(@pasv), '==', 1, 'One passive result for one check performed');
133for (0) { 125for (0) {
134 if ($pasv[$_]) { 126 if ($pasv[$_]) {
135 like($pasv[$_], '/^\[\d+\] PROCESS_SERVICE_CHECK_RESULT;flint;serv;2;' . $responce_re[2] . '$/', 'proper result for passive check'); 127 like($pasv[$_], '/^\[\d+\] PROCESS_SERVICE_CHECK_RESULT;flint;serv;2;' . $response_re[2] . '$/', 'proper result for passive check');
136 } else { 128 } else {
137 fail('proper result for passive check'); 129 fail('proper result for passive check');
138 } 130 }
@@ -152,7 +144,7 @@ for (0, 1, 2, 3, 4) {
152 if ($pasv[$_]) { 144 if ($pasv[$_]) {
153 my $ret = $_; 145 my $ret = $_;
154 $ret = 9 if ($_ == 4); 146 $ret = 9 if ($_ == 4);
155 like($pasv[$_], '/^\[\d+\] PROCESS_SERVICE_CHECK_RESULT;flint;c' . $_ . ';' . $ret . ';' . $responce_re[$_] . '$/', "proper result for passive check $_"); 147 like($pasv[$_], '/^\[\d+\] PROCESS_SERVICE_CHECK_RESULT;flint;c' . $_ . ';' . $ret . ';' . $response_re[$_] . '$/', "proper result for passive check $_");
156 } else { 148 } else {
157 fail("proper result for passive check $_"); 149 fail("proper result for passive check $_");
158 } 150 }
diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t
new file mode 100644
index 0000000..eae98cc
--- /dev/null
+++ b/plugins/t/check_curl.t
@@ -0,0 +1,213 @@
1#! /usr/bin/perl -w -I ..
2#
3# HyperText Transfer Protocol (HTTP) Test via check_curl
4#
5#
6
7use strict;
8use Test::More;
9use POSIX qw/mktime strftime/;
10
11use vars qw($tests $has_ipv6);
12
13BEGIN {
14 use NPTest;
15 $has_ipv6 = NPTest::has_ipv6();
16 $tests = $has_ipv6 ? 59 : 57;
17 plan tests => $tests;
18}
19
20
21my $successOutput = '/OK.*HTTP.*second/';
22
23my $res;
24my $plugin = 'check_http';
25$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
26
27my $host_tcp_http = getTestParameter("NP_HOST_TCP_HTTP", "A host providing the HTTP Service (a web server)", "localhost");
28my $host_tcp_http_ipv6 = getTestParameter("NP_HOST_TCP_HTTP_IPV6", "An IPv6 address providing a HTTP Service (a web server)", "::1");
29my $host_tls_http = getTestParameter("NP_HOST_TLS_HTTP", "A host providing the HTTPS Service (a tls web server)", "localhost");
30my $host_tls_cert = getTestParameter("NP_HOST_TLS_CERT", "the common name of the certificate.", "localhost");
31my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
32my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
33my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
34my $host_tcp_http2 = getTestParameter("NP_HOST_TCP_HTTP2", "A host providing an index page containing the string 'monitoring'", "test.monitoring-plugins.org");
35my $host_tcp_proxy = getTestParameter("NP_HOST_TCP_PROXY", "A host providing a HTTP proxy with CONNECT support", "localhost");
36my $port_tcp_proxy = getTestParameter("NP_PORT_TCP_PROXY", "Port of the proxy with HTTP and CONNECT support", "3128");
37
38my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
39
40
41$res = NPTest->testCmd(
42 "./$plugin $host_tcp_http -wt 300 -ct 600"
43 );
44cmp_ok( $res->return_code, '==', 0, "Webserver $host_tcp_http responded" );
45like( $res->output, $successOutput, "Output OK" );
46
47if ($has_ipv6) {
48 # Test for IPv6 formatting
49 $res = NPTest->testCmd(
50 "./$plugin -I $host_tcp_http_ipv6 -wt 300 -ct 600"
51 );
52 cmp_ok( $res->return_code, '==', 0, "IPv6 URL formatting is working" );
53 like( $res->output, $successOutput, "Output OK" );
54}
55
56$res = NPTest->testCmd(
57 "./$plugin $host_tcp_http -wt 300 -ct 600 -v -v -v -k 'bob:there' -k 'carl:frown'"
58 );
59like( $res->output, '/bob:there\r\ncarl:frown\r\n/', "Got headers with multiple -k options" );
60
61$res = NPTest->testCmd(
62 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
63 );
64cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
65# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!)
66like( $res->output, "/HTTP CRITICAL - Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK");
67
68$res = NPTest->testCmd(
69 "./$plugin $hostname_invalid -wt 1 -ct 2"
70 );
71cmp_ok( $res->return_code, '==', 2, "Webserver $hostname_invalid not valid" );
72# The first part of the message comes from the OS catalogue, so cannot check this.
73# On Debian, it is Name or service not known, on Darwin, it is No address associated with nodename
74# Is also possible to get a socket timeout if DNS is not responding fast enough
75# cURL gives us consistent strings from it's own 'lib/strerror.c'
76like( $res->output, "/cURL returned 6 - Could not resolve host:/", "Output OK");
77
78# host header checks
79$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http");
80like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
81like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
82
83$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http -p 80");
84like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
85like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
86
87$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
88like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
89like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
90
91$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
92like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
93like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
94
95$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80 -k 'Host: testhost:8001'");
96like( $res->output, '/^Host: testhost:8001\s*$/ms', "Host Header OK" );
97like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
98
99$res = NPTest->testCmd("./$plugin -v -I $host_tcp_http -p 80 -k 'Host: testhost:8001'");
100like( $res->output, '/^Host: testhost:8001\s*$/ms', "Host Header OK" );
101like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
102
103SKIP: {
104 skip "No internet access", 4 if $internet_access eq "no";
105
106 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http -S");
107 like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
108
109 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:8080 -S -p 443");
110 like( $res->output, '/^Host: '.$host_tls_http.':8080\s*$/ms', "Host Header OK" );
111
112 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:443 -S -p 443");
113 like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
114
115 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http -D -S -p 443");
116 like( $res->output, '/(^Host: '.$host_tls_http.'\s*$)|(cURL returned 60)/ms', "Host Header OK" );
117};
118
119SKIP: {
120 skip "No host serving monitoring in index file", 7 unless $host_tcp_http2;
121
122 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring'" );
123 cmp_ok( $res->return_code, "==", 0, "Got a reference to 'monitoring'");
124
125 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
126 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
127 like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'");
128
129 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
130 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
131
132 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
133 cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
134 like ( $res->output, "/pattern found/", "Error message says 'pattern found'");
135
136 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
137 cmp_ok( $res->return_code, "==", 0, "And also when not found");
138}
139SKIP: {
140 skip "No internet access", 28 if $internet_access eq "no";
141
142 $res = NPTest->testCmd(
143 "./$plugin --ssl $host_tls_http"
144 );
145 cmp_ok( $res->return_code, '==', 0, "Can read https for $host_tls_http" );
146
147 $res = NPTest->testCmd( "./$plugin -C 1 --ssl $host_tls_http" );
148 cmp_ok( $res->return_code, '==', 0, "Checking certificate for $host_tls_http");
149 like ( $res->output, "/Certificate '$host_tls_cert' will expire on/", "Output OK" );
150 my $saved_cert_output = $res->output;
151
152 $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
153 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
154 like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
155
156 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
157 is( $res->return_code, 0, "Old syntax for cert checking okay" );
158 is( $res->output, $saved_cert_output, "Same output as new syntax" );
159
160 $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
161 is( $res->return_code, 0, "Updated syntax for cert checking okay" );
162 is( $res->output, $saved_cert_output, "Same output as new syntax" );
163
164 $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
165 cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
166
167 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
168 cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
169
170 # run some certificate checks with faketime
171 SKIP: {
172 skip "No faketime binary found", 12 if !$faketime;
173 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
174 like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output");
175 is( $res->return_code, 0, "Catch cert output exit code" );
176 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
177 if(!defined $year) {
178 die("parsing date failed from: ".$res->output);
179 }
180 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
181 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
182 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
183 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
184 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date");
185 is( $res->return_code, 2, "Output on expire date" );
186
187 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
188 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
189 is( $res->return_code, 2, "cert expires in 1 second exit code" );
190
191 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
192 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
193 is( $res->return_code, 2, "cert expires in 2 minutes exit code" );
194
195 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
196 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
197 is( $res->return_code, 2, "cert expires in 2 hours exit code" );
198
199 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
200 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output");
201 is( $res->return_code, 2, "Certificate expired exit code" );
202 };
203
204 $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
205 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
206 like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
207
208 $res = NPTest->testCmd( "./$plugin -H www.mozilla.com -u /firefox -f curl" );
209 is( $res->return_code, 0, "Redirection based on location is okay");
210
211 $res = NPTest->testCmd( "./$plugin -H www.mozilla.com --extended-perfdata" );
212 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
213}
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t
index fdd8769..ca035ce 100644
--- a/plugins/t/check_disk.t
+++ b/plugins/t/check_disk.t
@@ -23,7 +23,7 @@ my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to anoth
23if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") { 23if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
24 plan skip_all => "Need 2 mountpoints to test"; 24 plan skip_all => "Need 2 mountpoints to test";
25} else { 25} else {
26 plan tests => 78; 26 plan tests => 88;
27} 27}
28 28
29$result = NPTest->testCmd( 29$result = NPTest->testCmd(
@@ -88,8 +88,9 @@ $result = NPTest->testCmd(
88 ); 88 );
89$_ = $result->perf_output; 89$_ = $result->perf_output;
90my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 90my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
91is ($warn_absth_data, $total_absth_data - 20, "Wrong warning in perf data using absolute thresholds"); 91# default unit is MiB, but perfdata is always bytes
92is ($crit_absth_data, $total_absth_data - 10, "Wrong critical in perf data using absolute thresholds"); 92is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds");
93is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds");
93 94
94# Then check percent thresholds. 95# Then check percent thresholds.
95$result = NPTest->testCmd( 96$result = NPTest->testCmd(
@@ -119,7 +120,7 @@ like ( $result->only_output, qr/$more_free/, "Have disk name in text");
119$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" ); 120$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" );
120cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free"); 121cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free");
121$_ = $result->output; 122$_ = $result->output;
122my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+) MB .* (\d+) MB /g); 123my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
123my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2; 124my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
124 125
125 126
@@ -325,19 +326,19 @@ cmp_ok( $result->return_code, '==', 0, "grouping: exit ok if the sum of free meg
325$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all - 1) ." -c ". ($free_mb_on_all - 1) ." -p $mountpoint_valid -g group -p $mountpoint2_valid" ); 326$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all - 1) ." -c ". ($free_mb_on_all - 1) ." -p $mountpoint_valid -g group -p $mountpoint2_valid" );
326cmp_ok( $result->return_code, '==', 3, "Invalid options: -p must come after groupname"); 327cmp_ok( $result->return_code, '==', 3, "Invalid options: -p must come after groupname");
327 328
328# regex: exit unknown if given regex is not compileable 329# regex: exit unknown if given regex is not compilable
329$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -r '('" ); 330$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -r '('" );
330cmp_ok( $result->return_code, '==', 3, "Exit UNKNOWN if regex is not compileable"); 331cmp_ok( $result->return_code, '==', 3, "Exit UNKNOWN if regex is not compilable");
331 332
332# ignore: exit unknown, if all pathes are deselected using -i 333# ignore: exit unknown, if all paths are deselected using -i
333$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '$mountpoint_valid' -i '$mountpoint2_valid'" ); 334$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '$mountpoint_valid' -i '$mountpoint2_valid'" );
334cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored (case sensitive)"); 335cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored (case sensitive)");
335 336
336# ignore: exit unknown, if all pathes are deselected using -I 337# ignore: exit unknown, if all paths are deselected using -I
337$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -I '".uc($mountpoint_valid)."' -I '".uc($mountpoint2_valid)."'" ); 338$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -I '".uc($mountpoint_valid)."' -I '".uc($mountpoint2_valid)."'" );
338cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored (case insensitive)"); 339cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored (case insensitive)");
339 340
340# ignore: exit unknown, if all pathes are deselected using -i 341# ignore: exit unknown, if all paths are deselected using -i
341$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '.*'" ); 342$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '.*'" );
342cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored using -i '.*'"); 343cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored using -i '.*'");
343 344
@@ -346,7 +347,32 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mo
346like( $result->output, qr/$mountpoint_valid/, "output data does have $mountpoint_valid in it"); 347like( $result->output, qr/$mountpoint_valid/, "output data does have $mountpoint_valid in it");
347unlike( $result->output, qr/$mountpoint2_valid/, "output data does not have $mountpoint2_valid in it"); 348unlike( $result->output, qr/$mountpoint2_valid/, "output data does not have $mountpoint2_valid in it");
348 349
349# ignore: test if all pathes are listed when ignore regex doesn't match 350# ignore: test if all paths are listed when ignore regex doesn't match
350$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '^barbazJodsf\$'"); 351$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '^barbazJodsf\$'");
351like( $result->output, qr/$mountpoint_valid/, "ignore: output data does have $mountpoint_valid when regex doesn't match"); 352like( $result->output, qr/$mountpoint_valid/, "ignore: output data does have $mountpoint_valid when regex doesn't match");
352like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mountpoint2_valid when regex doesn't match"); 353like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mountpoint2_valid when regex doesn't match");
354
355# ignore-missing: exit okay, when fs is not accessible
356$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
357cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
358like( $result->output, '/^DISK OK - No disks were found for provided parameters; - ignored paths: /bob;.*$/', 'Output OK');
359
360# ignore-missing: exit okay, when regex does not match
361$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
362cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
363like( $result->output, '/^DISK OK - No disks were found for provided parameters;.*$/', 'Output OK');
364
365# ignore-missing: exit okay, when fs with exact match (-E) is not found
366$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
367cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
368like( $result->output, '/^DISK OK - No disks were found for provided parameters; - ignored paths: /etc;.*$/', 'Output OK');
369
370# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
371$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
372cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
373like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
374
375# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
376$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
377cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
378like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); \ No newline at end of file
diff --git a/plugins/t/check_dns.t b/plugins/t/check_dns.t
index cdfbe60..afb2062 100644
--- a/plugins/t/check_dns.t
+++ b/plugins/t/check_dns.t
@@ -10,7 +10,7 @@ use NPTest;
10 10
11plan skip_all => "check_dns not compiled" unless (-x "check_dns"); 11plan skip_all => "check_dns not compiled" unless (-x "check_dns");
12 12
13plan tests => 19; 13plan tests => 23;
14 14
15my $successOutput = '/DNS OK: [\.0-9]+ seconds? response time/'; 15my $successOutput = '/DNS OK: [\.0-9]+ seconds? response time/';
16 16
@@ -105,3 +105,11 @@ cmp_ok( $res->return_code, '==', 0, "Got expected address");
105$res = NPTest->testCmd("./check_dns -H $hostname_valid -a $hostname_invalid_cidr -t 5"); 105$res = NPTest->testCmd("./check_dns -H $hostname_valid -a $hostname_invalid_cidr -t 5");
106cmp_ok( $res->return_code, '==', 2, "Got wrong address"); 106cmp_ok( $res->return_code, '==', 2, "Got wrong address");
107like ( $res->output, "/^DNS CRITICAL.*expected '$hostname_invalid_cidr' but got '$hostname_valid_ip'".'$/', "Output OK"); 107like ( $res->output, "/^DNS CRITICAL.*expected '$hostname_invalid_cidr' but got '$hostname_valid_ip'".'$/', "Output OK");
108
109$res = NPTest->testCmd("./check_dns -H $hostname_valid -n");
110cmp_ok( $res->return_code, '==', 2, "Found $hostname_valid");
111like ( $res->output, "/^DNS CRITICAL.*Domain '$hostname_valid' was found by the server:/", "Output OK");
112
113$res = NPTest->testCmd("./check_dns -H $hostname_invalid -n");
114cmp_ok( $res->return_code, '==', 0, "Did not find $hostname_invalid");
115like ( $res->output, $successOutput, "Output OK" );
diff --git a/plugins/t/check_fping.t b/plugins/t/check_fping.t
index 08692e4..67b357b 100644
--- a/plugins/t/check_fping.t
+++ b/plugins/t/check_fping.t
@@ -5,40 +5,30 @@
5# 5#
6 6
7use strict; 7use strict;
8use Test; 8use Test::More;
9use NPTest; 9use NPTest;
10 10
11use vars qw($tests); 11my $host_responsive = getTestParameter("NP_HOST_RESPONSIVE", "The hostname of system responsive to network requests", "localhost");
12my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
13my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
12 14
13BEGIN {$tests = 4; plan tests => $tests} 15my $res;
14
15my $successOutput = '/^FPING OK - /';
16my $failureOutput = '/^FPING CRITICAL - /';
17
18my $host_responsive = getTestParameter( "host_responsive", "NP_HOST_RESPONSIVE", "localhost",
19 "The hostname of system responsive to network requests" );
20
21my $host_nonresponsive = getTestParameter( "host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
22 "The hostname of system not responsive to network requests" );
23
24my $hostname_invalid = getTestParameter( "hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
25 "An invalid (not known to DNS) hostname" );
26
27
28my $t;
29 16
30my $fping = qx(which fping 2> /dev/null); 17my $fping = qx(which fping 2> /dev/null);
31chomp($fping); 18chomp($fping);
32if( ! -x "./check_fping") { 19if( ! -x "./check_fping") {
33 $t += skipMissingCmd( "./check_fping", $tests ); 20 plan skip_all => "check_fping not found, skipping tests";
34} 21}
35elsif ( $> != 0 && (!$fping || ! -u $fping)) { 22elsif ( !$fping || !-x $fping ) {
36 $t += skipMsg( "./check_fping", $tests ); 23 plan skip_all => "fping not found or cannot be executed, skipping tests";
37} else { 24} else {
38 $t += checkCmd( "./check_fping $host_responsive", 0, $successOutput ); 25 plan tests => 3;
39 $t += checkCmd( "./check_fping $host_nonresponsive", [ 1, 2 ] ); 26 $res = NPTest->testCmd( "./check_fping $host_responsive" );
40 $t += checkCmd( "./check_fping $hostname_invalid", [ 1, 2 ] ); 27 cmp_ok( $res->return_code, '==', 0, "Responsive host returns OK");
41}
42 28
43exit(0) if defined($Test::Harness::VERSION); 29 $res = NPTest->testCmd( "./check_fping $host_nonresponsive" );
44exit($tests - $t); 30 cmp_ok( $res->return_code, '==', 2, "Non-Responsive host returns Critical");
31
32 $res = NPTest->testCmd( "./check_fping $hostname_invalid" );
33 cmp_ok( $res->return_code, '==', 3, "Invalid host returns Unknown");
34}
diff --git a/plugins/t/check_ftp.t b/plugins/t/check_ftp.t
index de6831b..93a7d7c 100644
--- a/plugins/t/check_ftp.t
+++ b/plugins/t/check_ftp.t
@@ -11,14 +11,9 @@ use NPTest;
11use vars qw($tests); 11use vars qw($tests);
12BEGIN {$tests = 4; plan tests => $tests} 12BEGIN {$tests = 4; plan tests => $tests}
13 13
14my $host_tcp_ftp = getTestParameter( "host_tcp_ftp", "NP_HOST_TCP_FTP", "localhost", 14my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing the FTP Service (an FTP server)", "localhost");
15 "A host providing the FTP Service (an FTP server)"); 15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
16 16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
17my $host_nonresponsive = getTestParameter( "host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
18 "The hostname of system not responsive to network requests" );
19
20my $hostname_invalid = getTestParameter( "hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
21 "An invalid (not known to DNS) hostname" );
22 17
23my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/'; 18my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/';
24 19
diff --git a/plugins/t/check_http.t b/plugins/t/check_http.t
index 8bd484a..1f2fbdf 100644
--- a/plugins/t/check_http.t
+++ b/plugins/t/check_http.t
@@ -14,56 +14,41 @@ plan tests => 49;
14my $successOutput = '/OK.*HTTP.*second/'; 14my $successOutput = '/OK.*HTTP.*second/';
15 15
16my $res; 16my $res;
17 17my $plugin = 'check_http';
18my $host_tcp_http = getTestParameter( "NP_HOST_TCP_HTTP", 18$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
19 "A host providing the HTTP Service (a web server)", 19
20 "localhost" ); 20my $host_tcp_http = getTestParameter("NP_HOST_TCP_HTTP", "A host providing the HTTP Service (a web server)", "localhost");
21 21my $host_tls_http = getTestParameter("NP_HOST_TLS_HTTP", "A host providing the HTTPS Service (a tls web server)", "localhost");
22my $host_tls_http = getTestParameter( "host_tls_http", "NP_HOST_TLS_HTTP", "localhost", 22my $host_tls_cert = getTestParameter("NP_HOST_TLS_CERT", "the common name of the certificate.", "localhost");
23 "A host providing the HTTPS Service (a tls web server)" ); 23my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
24 24my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
25my $host_tls_cert = getTestParameter( "host_tls_cert", "NP_HOST_TLS_CERT", "localhost", 25my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
26 "the common name of the certificate." ); 26my $host_tcp_http2 = getTestParameter("NP_HOST_TCP_HTTP2", "A host providing an index page containing the string 'monitoring'", "test.monitoring-plugins.org");
27 27my $host_tcp_proxy = getTestParameter("NP_HOST_TCP_PROXY", "A host providing a HTTP proxy with CONNECT support", "localhost");
28 28my $port_tcp_proxy = getTestParameter("NP_PORT_TCP_PROXY", "Port of the proxy with HTTP and CONNECT support", "3128");
29my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE",
30 "The hostname of system not responsive to network requests",
31 "10.0.0.1" );
32
33my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
34 "An invalid (not known to DNS) hostname",
35 "nosuchhost");
36
37my $internet_access = getTestParameter( "NP_INTERNET_ACCESS",
38 "Is this system directly connected to the internet?",
39 "yes");
40
41my $host_tcp_http2 = getTestParameter( "NP_HOST_TCP_HTTP2",
42 "A host providing an index page containing the string 'monitoring'",
43 "test.monitoring-plugins.org" );
44 29
45my $faketime = -x '/usr/bin/faketime' ? 1 : 0; 30my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
46 31
47 32
48$res = NPTest->testCmd( 33$res = NPTest->testCmd(
49 "./check_http $host_tcp_http -wt 300 -ct 600" 34 "./$plugin $host_tcp_http -wt 300 -ct 600"
50 ); 35 );
51cmp_ok( $res->return_code, '==', 0, "Webserver $host_tcp_http responded" ); 36cmp_ok( $res->return_code, '==', 0, "Webserver $host_tcp_http responded" );
52like( $res->output, $successOutput, "Output OK" ); 37like( $res->output, $successOutput, "Output OK" );
53 38
54$res = NPTest->testCmd( 39$res = NPTest->testCmd(
55 "./check_http $host_tcp_http -wt 300 -ct 600 -v -v -v -k 'bob:there' -k 'carl:frown'" 40 "./$plugin $host_tcp_http -wt 300 -ct 600 -v -v -v -k 'bob:there' -k 'carl:frown'"
56 ); 41 );
57like( $res->output, '/bob:there\r\ncarl:frown\r\n/', "Got headers with multiple -k options" ); 42like( $res->output, '/bob:there\r\ncarl:frown\r\n/', "Got headers with multiple -k options" );
58 43
59$res = NPTest->testCmd( 44$res = NPTest->testCmd(
60 "./check_http $host_nonresponsive -wt 1 -ct 2 -t 3" 45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
61 ); 46 );
62cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); 47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
63cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK"); 48cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK");
64 49
65$res = NPTest->testCmd( 50$res = NPTest->testCmd(
66 "./check_http $hostname_invalid -wt 1 -ct 2" 51 "./$plugin $hostname_invalid -wt 1 -ct 2"
67 ); 52 );
68cmp_ok( $res->return_code, '==', 2, "Webserver $hostname_invalid not valid" ); 53cmp_ok( $res->return_code, '==', 2, "Webserver $hostname_invalid not valid" );
69# The first part of the message comes from the OS catalogue, so cannot check this. 54# The first part of the message comes from the OS catalogue, so cannot check this.
@@ -72,86 +57,86 @@ cmp_ok( $res->return_code, '==', 2, "Webserver $hostname_invalid not valid" );
72like( $res->output, "/Unable to open TCP socket|Socket timeout after/", "Output OK"); 57like( $res->output, "/Unable to open TCP socket|Socket timeout after/", "Output OK");
73 58
74# host header checks 59# host header checks
75$res = NPTest->testCmd("./check_http -v -H $host_tcp_http"); 60$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http");
76like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" ); 61like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
77 62
78$res = NPTest->testCmd("./check_http -v -H $host_tcp_http -p 80"); 63$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http -p 80");
79like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" ); 64like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
80 65
81$res = NPTest->testCmd("./check_http -v -H $host_tcp_http:8080 -p 80"); 66$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
82like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" ); 67like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
83 68
84$res = NPTest->testCmd("./check_http -v -H $host_tcp_http:8080 -p 80"); 69$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
85like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" ); 70like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
86 71
87SKIP: { 72SKIP: {
88 skip "No internet access", 3 if $internet_access eq "no"; 73 skip "No internet access", 3 if $internet_access eq "no";
89 74
90 $res = NPTest->testCmd("./check_http -v -H $host_tls_http -S"); 75 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http -S");
91 like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" ); 76 like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
92 77
93 $res = NPTest->testCmd("./check_http -v -H $host_tls_http:8080 -S -p 443"); 78 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:8080 -S -p 443");
94 like( $res->output, '/^Host: '.$host_tls_http.':8080\s*$/ms', "Host Header OK" ); 79 like( $res->output, '/^Host: '.$host_tls_http.':8080\s*$/ms', "Host Header OK" );
95 80
96 $res = NPTest->testCmd("./check_http -v -H $host_tls_http:443 -S -p 443"); 81 $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:443 -S -p 443");
97 like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" ); 82 like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
98}; 83};
99 84
100SKIP: { 85SKIP: {
101 skip "No host serving monitoring in index file", 7 unless $host_tcp_http2; 86 skip "No host serving monitoring in index file", 7 unless $host_tcp_http2;
102 87
103 $res = NPTest->testCmd( "./check_http -H $host_tcp_http2 -r 'monitoring'" ); 88 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring'" );
104 cmp_ok( $res->return_code, "==", 0, "Got a reference to 'monitoring'"); 89 cmp_ok( $res->return_code, "==", 0, "Got a reference to 'monitoring'");
105 90
106 $res = NPTest->testCmd( "./check_http -H $host_tcp_http2 -r 'mONiTORing'" ); 91 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
107 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'"); 92 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
108 like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'"); 93 like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'");
109 94
110 $res = NPTest->testCmd( "./check_http -H $host_tcp_http2 -R 'mONiTORing'" ); 95 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
111 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'"); 96 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
112 97
113 $res = NPTest->testCmd( "./check_http -H $host_tcp_http2 -r 'monitoring' --invert-regex" ); 98 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
114 cmp_ok( $res->return_code, "==", 2, "Invert results work when found"); 99 cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
115 like ( $res->output, "/pattern found/", "Error message says 'pattern found'"); 100 like ( $res->output, "/pattern found/", "Error message says 'pattern found'");
116 101
117 $res = NPTest->testCmd( "./check_http -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" ); 102 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
118 cmp_ok( $res->return_code, "==", 0, "And also when not found"); 103 cmp_ok( $res->return_code, "==", 0, "And also when not found");
119} 104}
120SKIP: { 105SKIP: {
121 skip "No internet access", 16 if $internet_access eq "no"; 106 skip "No internet access", 22 if $internet_access eq "no";
122 107
123 $res = NPTest->testCmd( 108 $res = NPTest->testCmd(
124 "./check_http --ssl $host_tls_http" 109 "./$plugin --ssl $host_tls_http"
125 ); 110 );
126 cmp_ok( $res->return_code, '==', 0, "Can read https for $host_tls_http" ); 111 cmp_ok( $res->return_code, '==', 0, "Can read https for $host_tls_http" );
127 112
128 $res = NPTest->testCmd( "./check_http -C 1 --ssl $host_tls_http" ); 113 $res = NPTest->testCmd( "./$plugin -C 1 --ssl $host_tls_http" );
129 cmp_ok( $res->return_code, '==', 0, "Checking certificate for $host_tls_http"); 114 cmp_ok( $res->return_code, '==', 0, "Checking certificate for $host_tls_http");
130 like ( $res->output, "/Certificate '$host_tls_cert' will expire on/", "Output OK" ); 115 like ( $res->output, "/Certificate '$host_tls_cert' will expire on/", "Output OK" );
131 my $saved_cert_output = $res->output; 116 my $saved_cert_output = $res->output;
132 117
133 $res = NPTest->testCmd( "./check_http -C 8000,1 --ssl $host_tls_http" ); 118 $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
134 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http"); 119 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
135 like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" ); 120 like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
136 121
137 $res = NPTest->testCmd( "./check_http $host_tls_http -C 1" ); 122 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
138 is( $res->return_code, 0, "Old syntax for cert checking okay" ); 123 is( $res->return_code, 0, "Old syntax for cert checking okay" );
139 is( $res->output, $saved_cert_output, "Same output as new syntax" ); 124 is( $res->output, $saved_cert_output, "Same output as new syntax" );
140 125
141 $res = NPTest->testCmd( "./check_http -H $host_tls_http -C 1" ); 126 $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
142 is( $res->return_code, 0, "Updated syntax for cert checking okay" ); 127 is( $res->return_code, 0, "Updated syntax for cert checking okay" );
143 is( $res->output, $saved_cert_output, "Same output as new syntax" ); 128 is( $res->output, $saved_cert_output, "Same output as new syntax" );
144 129
145 $res = NPTest->testCmd( "./check_http -C 1 $host_tls_http" ); 130 $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
146 cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added"); 131 cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
147 132
148 $res = NPTest->testCmd( "./check_http $host_tls_http -C 1" ); 133 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
149 cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works"); 134 cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
150 135
151 # run some certificate checks with faketime 136 # run some certificate checks with faketime
152 SKIP: { 137 SKIP: {
153 skip "No faketime binary found", 12 if !$faketime; 138 skip "No faketime binary found", 7 if !$faketime;
154 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./check_http -C 1 $host_tls_http"); 139 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
155 like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output"); 140 like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output");
156 is( $res->return_code, 0, "Catch cert output exit code" ); 141 is( $res->return_code, 0, "Catch cert output exit code" );
157 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/); 142 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
@@ -161,40 +146,45 @@ SKIP: {
161 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11}; 146 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
162 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900); 147 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
163 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts)); 148 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
164 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_http -C 1 $host_tls_http"); 149 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
165 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date"); 150 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date");
166 is( $res->return_code, 2, "Output on expire date" );
167 151
168 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./check_http -C 1 $host_tls_http"); 152 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
169 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output"); 153 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
170 is( $res->return_code, 2, "cert expires in 1 second exit code" );
171 154
172 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./check_http -C 1 $host_tls_http"); 155 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
173 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output"); 156 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
174 is( $res->return_code, 2, "cert expires in 2 minutes exit code" );
175 157
176 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./check_http -C 1 $host_tls_http"); 158 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
177 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output"); 159 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
178 is( $res->return_code, 2, "cert expires in 2 hours exit code" );
179 160
180 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_http -C 1 $host_tls_http"); 161 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
181 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output"); 162 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output");
182 is( $res->return_code, 2, "Certificate expired exit code" );
183 }; 163 };
184 164
185 $res = NPTest->testCmd( "./check_http --ssl $host_tls_http -E" ); 165 $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
186 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); 166 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
187 like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' ); 167 like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
188 168
189 $res = NPTest->testCmd( 169 $res = NPTest->testCmd( "./$plugin -H www.mozilla.com -u /firefox -f follow" );
190 "./check_http --ssl -H www.e-paycobalt.com"
191 );
192 cmp_ok( $res->return_code, "==", 0, "Can read https for www.e-paycobalt.com (uses AES certificate)" );
193
194
195 $res = NPTest->testCmd( "./check_http -H www.mozilla.com -u /firefox -f follow" );
196 is( $res->return_code, 0, "Redirection based on location is okay"); 170 is( $res->return_code, 0, "Redirection based on location is okay");
197 171
198 $res = NPTest->testCmd( "./check_http -H www.mozilla.com --extended-perfdata" ); 172 $res = NPTest->testCmd( "./$plugin -H www.mozilla.com --extended-perfdata" );
199 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); 173 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
200} 174}
175
176SKIP: {
177 skip "No internet access or proxy configured", 6 if $internet_access eq "no" or ! $host_tcp_proxy;
178
179 $res = NPTest->testCmd( "./$plugin -I $host_tcp_proxy -p $port_tcp_proxy -u http://$host_tcp_http -e 200,301,302");
180 is( $res->return_code, 0, "Proxy HTTP works");
181 like($res->output, qr/OK: Status line output matched/, "Proxy HTTP Output is sufficient");
182
183 $res = NPTest->testCmd( "./$plugin -I $host_tcp_proxy -p $port_tcp_proxy -H $host_tls_http -S -j CONNECT");
184 is( $res->return_code, 0, "Proxy HTTP CONNECT works");
185 like($res->output, qr/HTTP OK:/, "Proxy HTTP CONNECT output sufficient");
186
187 $res = NPTest->testCmd( "./$plugin -I $host_tcp_proxy -p $port_tcp_proxy -H $host_tls_http -S -j CONNECT:HEAD");
188 is( $res->return_code, 0, "Proxy HTTP CONNECT works with override method");
189 like($res->output, qr/HTTP OK:/, "Proxy HTTP CONNECT output sufficient");
190}
diff --git a/plugins/t/check_imap.t b/plugins/t/check_imap.t
index 9c6eae1..7c74e56 100644
--- a/plugins/t/check_imap.t
+++ b/plugins/t/check_imap.t
@@ -8,17 +8,10 @@ use strict;
8use Test::More tests => 7; 8use Test::More tests => 7;
9use NPTest; 9use NPTest;
10 10
11my $host_tcp_smtp = getTestParameter( "host_tcp_smtp", "NP_HOST_TCP_SMTP", "mailhost", 11my $host_tcp_smtp = getTestParameter("NP_HOST_TCP_SMTP", "A host providing an STMP Service (a mail server)", "mailhost");
12 "A host providing an STMP Service (a mail server)"); 12my $host_tcp_imap = getTestParameter("NP_HOST_TCP_IMAP", "A host providing an IMAP Service (a mail server)", $host_tcp_smtp);
13 13my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
14my $host_tcp_imap = getTestParameter( "host_tcp_imap", "NP_HOST_TCP_IMAP", $host_tcp_smtp, 14my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
15 "A host providing an IMAP Service (a mail server)");
16
17my $host_nonresponsive = getTestParameter( "host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
18 "The hostname of system not responsive to network requests" );
19
20my $hostname_invalid = getTestParameter( "hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
21 "An invalid (not known to DNS) hostname" );
22 15
23my $t; 16my $t;
24 17
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index 7a708d5..fcdae17 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -10,23 +10,9 @@ use NPTest;
10 10
11plan tests => 10; 11plan tests => 10;
12 12
13my $host_tcp_jabber = getTestParameter( 13my $host_tcp_jabber = getTestParameter("NP_HOST_TCP_JABBER", "A host providing the Jabber Service", "jabber.de");
14 "NP_HOST_TCP_JABBER", 14my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
15 "A host providing the Jabber Service", 15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
16 "jabber.org"
17 );
18
19my $host_nonresponsive = getTestParameter(
20 "NP_HOST_NONRESPONSIVE",
21 "The hostname of system not responsive to network requests",
22 "10.0.0.1",
23 );
24
25my $hostname_invalid = getTestParameter(
26 "NP_HOSTNAME_INVALID",
27 "An invalid (not known to DNS) hostname",
28 "nosuchhost",
29 );
30 16
31 17
32my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/'; 18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/';
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t
index b8944d4..b8a4a76 100644
--- a/plugins/t/check_ldap.t
+++ b/plugins/t/check_ldap.t
@@ -9,19 +9,10 @@ use warnings;
9use Test::More; 9use Test::More;
10use NPTest; 10use NPTest;
11 11
12my $host_tcp_ldap = getTestParameter("NP_HOST_TCP_LDAP", 12my $host_tcp_ldap = getTestParameter("NP_HOST_TCP_LDAP", "A host providing the LDAP Service", "localhost");
13 "A host providing the LDAP Service", 13my $ldap_base_dn = getTestParameter("NP_LDAP_BASE_DN", "A base dn for the LDAP Service", "cn=admin");
14 "localhost" ); 14my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
15 15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
16my $ldap_base_dn = getTestParameter("NP_LDAP_BASE_DN",
17 "A base dn for the LDAP Service",
18 "cn=admin" );
19
20my $host_nonresponsive = getTestParameter("host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
21 "The hostname of system not responsive to network requests" );
22
23my $hostname_invalid = getTestParameter("hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
24 "An invalid (not known to DNS) hostname" );
25 16
26my($result, $cmd); 17my($result, $cmd);
27my $command = './check_ldap'; 18my $command = './check_ldap';
diff --git a/plugins/t/check_load.t b/plugins/t/check_load.t
index 55f6f75..bba8947 100644
--- a/plugins/t/check_load.t
+++ b/plugins/t/check_load.t
@@ -11,10 +11,12 @@ use NPTest;
11my $res; 11my $res;
12 12
13my $loadValue = "[0-9]+\.?[0-9]+"; 13my $loadValue = "[0-9]+\.?[0-9]+";
14my $successOutput = "/^OK - load average: $loadValue, $loadValue, $loadValue/"; 14my $successOutput = "/^LOAD OK - total load average: $loadValue, $loadValue, $loadValue/";
15my $failureOutput = "/^CRITICAL - load average: $loadValue, $loadValue, $loadValue/"; 15my $successScaledOutput = "/^LOAD OK - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
16my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/";
17my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
16 18
17plan tests => 11; 19plan tests => 13;
18 20
19$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" ); 21$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" );
20cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); 22cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
@@ -26,7 +28,7 @@ like( $res->output, $failureOutput, "Output OK");
26 28
27$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" ); 29$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" );
28cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division"); 30cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division");
29like( $res->output, $failureOutput, "Output OK"); 31like( $res->output, $failurScaledOutput, "Output OK");
30 32
31$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" ); 33$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" );
32cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments"); 34cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments");
@@ -34,3 +36,8 @@ like( $res->output, $successOutput, "Output OK");
34like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)"); 36like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)");
35like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)"); 37like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)");
36like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)"); 38like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)");
39
40
41$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" );
42cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
43like( $res->output, $successScaledOutput, "Output OK");
diff --git a/plugins/t/check_mysql.t b/plugins/t/check_mysql.t
index 28cd4cd..baf3acc 100644
--- a/plugins/t/check_mysql.t
+++ b/plugins/t/check_mysql.t
@@ -5,7 +5,7 @@
5# 5#
6# 6#
7# These are the database permissions required for this test: 7# These are the database permissions required for this test:
8# GRANT SELECT ON $db.* TO $user@$host INDENTIFIED BY '$password'; 8# GRANT SELECT ON $db.* TO $user@$host IDENTIFIED BY '$password';
9# GRANT SUPER, REPLICATION CLIENT ON *.* TO $user@$host; 9# GRANT SUPER, REPLICATION CLIENT ON *.* TO $user@$host;
10# Check with: 10# Check with:
11# mysql -u$user -p$password -h$host $db 11# mysql -u$user -p$password -h$host $db
@@ -21,30 +21,11 @@ plan skip_all => "check_mysql not compiled" unless (-x "check_mysql");
21plan tests => 15; 21plan tests => 15;
22 22
23my $bad_login_output = '/Access denied for user /'; 23my $bad_login_output = '/Access denied for user /';
24my $mysqlserver = getTestParameter( 24my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no slaves setup");
25 "NP_MYSQL_SERVER", 25my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no slaves setup");
26 "A MySQL Server hostname or IP with no slaves setup" 26my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest");
27 ); 27my $with_slave = getTestParameter("NP_MYSQL_WITH_SLAVE", "MySQL server with slaves setup");
28my $mysqlsocket = getTestParameter( 28my $with_slave_login = getTestParameter("NP_MYSQL_WITH_SLAVE_LOGIN", "Login details for server with slave (requires REPLICATION CLIENT privileges)", $mysql_login_details || "-u test -ptest");
29 "NP_MYSQL_SOCKET",
30 "Full path to a MySQL Server socket with no slaves setup"
31 );
32my $mysql_login_details = getTestParameter(
33 "MYSQL_LOGIN_DETAILS",
34 "Command line parameters to specify login access (requires " .
35 "REPLICATION CLIENT privleges)",
36 "-u test -ptest",
37 );
38my $with_slave = getTestParameter(
39 "NP_MYSQL_WITH_SLAVE",
40 "MySQL server with slaves setup"
41 );
42my $with_slave_login = getTestParameter(
43 "NP_MYSQL_WITH_SLAVE_LOGIN",
44 "Login details for server with slave (requires REPLICATION CLIENT " .
45 "privleges)",
46 $mysql_login_details || "-u test -ptest"
47 );
48 29
49my $result; 30my $result;
50 31
diff --git a/plugins/t/check_mysql_query.t b/plugins/t/check_mysql_query.t
index 407af88..c30245b 100644
--- a/plugins/t/check_mysql_query.t
+++ b/plugins/t/check_mysql_query.t
@@ -17,15 +17,8 @@ use vars qw($tests);
17 17
18plan skip_all => "check_mysql_query not compiled" unless (-x "check_mysql_query"); 18plan skip_all => "check_mysql_query not compiled" unless (-x "check_mysql_query");
19 19
20my $mysqlserver = getTestParameter( 20my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server with no slaves setup");
21 "NP_MYSQL_SERVER", 21my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access", "-u user -ppw -d db");
22 "A MySQL Server with no slaves setup"
23 );
24my $mysql_login_details = getTestParameter(
25 "MYSQL_LOGIN_DETAILS",
26 "Command line parameters to specify login access",
27 "-u user -ppw -d db",
28 );
29my $result; 22my $result;
30 23
31if (! $mysqlserver) { 24if (! $mysqlserver) {
@@ -38,7 +31,7 @@ $result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver $
38cmp_ok( $result->return_code, '==', 0, "Can run query"); 31cmp_ok( $result->return_code, '==', 0, "Can run query");
39 32
40$result = NPTest->testCmd("./check_mysql_query -H $mysqlserver $mysql_login_details"); 33$result = NPTest->testCmd("./check_mysql_query -H $mysqlserver $mysql_login_details");
41cmp_ok( $result->return_code, '==', 3, "Missing query parmeter"); 34cmp_ok( $result->return_code, '==', 3, "Missing query parameter");
42like( $result->output, "/Must specify a SQL query to run/", "Missing query error message"); 35like( $result->output, "/Must specify a SQL query to run/", "Missing query error message");
43 36
44$result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver -u dummy -d mysql"); 37$result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver -u dummy -d mysql");
diff --git a/plugins/t/check_nagios.t b/plugins/t/check_nagios.t
index 81fc24d..f38f5e9 100644
--- a/plugins/t/check_nagios.t
+++ b/plugins/t/check_nagios.t
@@ -36,7 +36,7 @@ cmp_ok( $result->return_code, '==', 1, "Log over 5 minutes old" );
36like ( $result->output, $warningOutput, "Output for warning correct" ); 36like ( $result->output, $warningOutput, "Output for warning correct" );
37 37
38my $now = time; 38my $now = time;
39# This substitution is dependant on the testcase 39# This substitution is dependent on the testcase
40system( "perl -pe 's/1133537544/$now/' $nagios1 > $nagios1.tmp" ) == 0 or die "Problem with munging $nagios1"; 40system( "perl -pe 's/1133537544/$now/' $nagios1 > $nagios1.tmp" ) == 0 or die "Problem with munging $nagios1";
41 41
42$result = NPTest->testCmd( 42$result = NPTest->testCmd(
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t
index aa6dae4..1a1ebe3 100644
--- a/plugins/t/check_smtp.t
+++ b/plugins/t/check_smtp.t
@@ -8,12 +8,14 @@ use strict;
8use Test::More; 8use Test::More;
9use NPTest; 9use NPTest;
10 10
11my $host_tcp_smtp = getTestParameter( "NP_HOST_TCP_SMTP", 11my $host_tcp_smtp = getTestParameter( "NP_HOST_TCP_SMTP",
12 "A host providing an SMTP Service (a mail server)", "mailhost"); 12 "A host providing an SMTP Service (a mail server)", "mailhost");
13my $host_tcp_smtp_tls = getTestParameter( "NP_HOST_TCP_SMTP_TLS", 13my $host_tcp_smtp_starttls = getTestParameter( "NP_HOST_TCP_SMTP_STARTTLS",
14 "A host providing SMTP with STARTTLS", $host_tcp_smtp);
15my $host_tcp_smtp_nostarttls = getTestParameter( "NP_HOST_TCP_SMTP_NOSTARTTLS",
16 "A host providing SMTP without STARTTLS", "");
17my $host_tcp_smtp_tls = getTestParameter( "NP_HOST_TCP_SMTP_TLS",
14 "A host providing SMTP with TLS", $host_tcp_smtp); 18 "A host providing SMTP with TLS", $host_tcp_smtp);
15my $host_tcp_smtp_notls = getTestParameter( "NP_HOST_TCP_SMTP_NOTLS",
16 "A host providing SMTP without TLS", "");
17 19
18my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE", 20my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE",
19 "The hostname of system not responsive to network requests", "10.0.0.1" ); 21 "The hostname of system not responsive to network requests", "10.0.0.1" );
@@ -22,7 +24,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
22 "An invalid (not known to DNS) hostname", "nosuchhost" ); 24 "An invalid (not known to DNS) hostname", "nosuchhost" );
23my $res; 25my $res;
24 26
25plan tests => 10; 27plan tests => 16;
26 28
27SKIP: { 29SKIP: {
28 skip "No SMTP server defined", 4 unless $host_tcp_smtp; 30 skip "No SMTP server defined", 4 unless $host_tcp_smtp;
@@ -42,22 +44,38 @@ SKIP: {
42 local $TODO = "Output is over two lines"; 44 local $TODO = "Output is over two lines";
43 like ( $res->output, qr/^SMTP WARNING/, "Correct error message" ); 45 like ( $res->output, qr/^SMTP WARNING/, "Correct error message" );
44 } 46 }
47
48 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" );
49 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" );
50 like ($res->output, qr/^CRITICAL - Cannot make SSL connection\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port");
45} 51}
46 52
47SKIP: { 53SKIP: {
48 skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; 54 skip "No SMTP server with STARTTLS defined", 1 unless $host_tcp_smtp_starttls;
49 # SSL connection for TLS 55 # SSL connection for STARTTLS
50 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p 25 -S" ); 56 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_starttls -p 25 -S" );
51 is ($res->return_code, 0, "OK, with STARTTLS" ); 57 is ($res->return_code, 0, "OK, with STARTTLS" );
52} 58}
53 59
54SKIP: { 60SKIP: {
55 skip "No SMTP server without TLS defined", 2 unless $host_tcp_smtp_notls; 61 skip "No SMTP server without STARTTLS defined", 2 unless $host_tcp_smtp_nostarttls;
56 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_notls -p 25 -S" ); 62 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_nostarttls -p 25 -S" );
57 is ($res->return_code, 1, "OK, got warning from server without TLS"); 63 is ($res->return_code, 1, "OK, got warning from server without STARTTLS");
58 is ($res->output, "WARNING - TLS not supported by server", "Right error message" ); 64 is ($res->output, "WARNING - TLS not supported by server", "Right error message" );
59} 65}
60 66
67SKIP: {
68 skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls;
69 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" );
70 is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" );
71 like ($res->output, qr/^SMTP OK - /, "Check output of connecting to $host_tcp_smtp_tls with TLS" );
72
73 my $unused_port = 4465;
74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" );
75 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" );
76 like ($res->output, qr/^connect to address $host_tcp_smtp_tls and port $unused_port: Connection refused/, "Check output of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port");
77}
78
61$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" ); 79$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" );
62is ($res->return_code, 2, "CRITICAL - host non responding" ); 80is ($res->return_code, 2, "CRITICAL - host non responding" );
63 81
diff --git a/plugins/t/check_snmp.t b/plugins/t/check_snmp.t
index 9a6cd2b..576cc50 100644
--- a/plugins/t/check_snmp.t
+++ b/plugins/t/check_snmp.t
@@ -15,39 +15,33 @@ BEGIN {
15 15
16my $res; 16my $res;
17 17
18my $host_snmp = getTestParameter( "host_snmp", "NP_HOST_SNMP", "localhost", 18my $host_snmp = getTestParameter("NP_HOST_SNMP", "A host providing an SNMP Service", "localhost");
19 "A host providing an SNMP Service"); 19my $snmp_community = getTestParameter("NP_SNMP_COMMUNITY", "The SNMP Community string for SNMP Testing (assumes snmp v1)", "public");
20my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
22my $user_snmp = getTestParameter("NP_SNMP_USER", "An SNMP user", "auth_md5");
20 23
21my $snmp_community = getTestParameter( "snmp_community", "NP_SNMP_COMMUNITY", "public",
22 "The SNMP Community string for SNMP Testing (assumes snmp v1)" );
23
24my $host_nonresponsive = getTestParameter( "host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
25 "The hostname of system not responsive to network requests" );
26
27my $hostname_invalid = getTestParameter( "hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
28 "An invalid (not known to DNS) hostname" );
29my $user_snmp = getTestParameter( "user_snmp", "NP_SNMP_USER", "auth_md5", "An SNMP user");
30 24
31$res = NPTest->testCmd( "./check_snmp -t 1" ); 25$res = NPTest->testCmd( "./check_snmp -t 1" );
32is( $res->return_code, 3, "No host name" ); 26is( $res->return_code, 3, "No host name" );
33is( $res->output, "No host specified" ); 27is( $res->output, "No host specified" );
34 28
35$res = NPTest->testCmd( "./check_snmp -H fakehostname" ); 29$res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" );
36is( $res->return_code, 3, "No OIDs specified" ); 30is( $res->return_code, 3, "No OIDs specified" );
37is( $res->output, "No OIDs specified" ); 31is( $res->output, "No OIDs specified" );
38 32
39$res = NPTest->testCmd( "./check_snmp -H fakehost -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" );
40is( $res->return_code, 3, "Invalid seclevel" ); 34is( $res->return_code, 3, "Invalid seclevel" );
41like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" ); 35like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" );
42 36
43$res = NPTest->testCmd( "./check_snmp -H fakehost -o oids -P 3c" ); 37$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" );
44is( $res->return_code, 3, "Invalid protocol" ); 38is( $res->return_code, 3, "Invalid protocol" );
45like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" ); 39like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" );
46 40
47SKIP: { 41SKIP: {
48 skip "no snmp host defined", 50 if ( ! $host_snmp ); 42 skip "no snmp host defined", 50 if ( ! $host_snmp );
49 43
50 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); 44 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:");
51 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" ); 45 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" );
52 like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK"); 46 like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK");
53 $res->output =~ /^SNMP OK - (\d+)/; 47 $res->output =~ /^SNMP OK - (\d+)/;
@@ -57,111 +51,111 @@ SKIP: {
57 51
58 52
59 # some more threshold tests 53 # some more threshold tests
60 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c 1"); 54 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1");
61 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" ); 55 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" );
62 56
63 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c 1:"); 57 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:");
64 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" ); 58 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" );
65 59
66 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c ~:1"); 60 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1");
67 cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" ); 61 cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" );
68 62
69 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c 1:10"); 63 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10");
70 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" ); 64 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" );
71 65
72 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c \@1:10"); 66 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10");
73 cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" ); 67 cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" );
74 68
75 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c 10:1"); 69 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 10:1");
76 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" ); 70 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" );
77 71
78 72
79 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1:"); 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:");
80 cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" ); 74 cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" );
81 like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK"); 75 like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK");
82 76
83 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysDescr.0"); 77 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0");
84 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" ); 78 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" );
85 unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values"); 79 unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values");
86 80
87 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysDescr.0,system.sysDescr.0"); 81 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0");
88 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" ); 82 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" );
89 like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); 83 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
90 84
91 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0"); 85 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0");
92 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" ); 86 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" );
93 like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); 87 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
94 88
95 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1"); 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");
96 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" ); 90 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" );
97 like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format"); 91 like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format");
98 92
99 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1:"); 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:");
100 cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " ); 94 cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " );
101 like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format"); 95 like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format");
102 96
103 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0"); 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");
104 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" ); 98 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" );
105 like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format"); 99 like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format");
106 100
107 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2"); 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");
108 cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" ); 102 cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" );
109 like($res->output, "/^SNMP OK - 2 1/", "Got two values back" ); 103 like($res->output, "/^SNMP OK - 2 1/", "Got two values back" );
110 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); 104 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" );
111 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" ); 105 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
112 106
113 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2"); 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");
114 cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" ); 108 cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" );
115 like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" ); 109 like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" );
116 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); 110 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" );
117 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" ); 111 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
118 112
119 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1:"); 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:");
120 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses"); 114 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses");
121 like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses"); 115 like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses");
122 116
123 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0"); 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");
124 cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds"); 118 cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds");
125 like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format"); 119 like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format");
126 120
127 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3"); 121 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3");
128 $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/; 122 $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/;
129 my $lower = $1 - 0.05; 123 my $lower = $1 - 0.05;
130 my $higher = $1 + 0.05; 124 my $higher = $1 + 0.05;
131 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3 -w $lower -c $higher"); 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");
132 cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments"); 126 cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments");
133 127
134 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2"); 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");
135 cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold"); 129 cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold");
136 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"); 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");
137 131
138 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c ''"); 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 ''");
139 cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash"); 133 cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash");
140 134
141 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2"); 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");
142 cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check"); 136 cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check");
143 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed"); 137 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed");
144 138
145 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,,"); 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 ,,");
146 cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds"); 140 cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds");
147 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed"); 141 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed");
148 142
149 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec'"); 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'");
150 cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold"); 144 cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold");
151 like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric"); 145 like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric");
152 146
153 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o system.sysUpTime.0"); 147 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0");
154 cmp_ok( $res->return_code, '==', 0, "Timetick used as a string"); 148 cmp_ok( $res->return_code, '==', 0, "Timetick used as a string");
155 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"); 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");
156 150
157 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1"); 151 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1");
158 cmp_ok( $res->return_code, '==', 0, "snmp response without datatype"); 152 cmp_ok( $res->return_code, '==', 0, "snmp response without datatype");
159 like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" ); 153 like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" );
160} 154}
161 155
162SKIP: { 156SKIP: {
163 skip "no SNMP user defined", 1 if ( ! $user_snmp ); 157 skip "no SNMP user defined", 1 if ( ! $user_snmp );
164 $res = NPTest->testCmd( "./check_snmp -H $host_snmp -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv"); 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");
165 like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" ); 159 like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" );
166} 160}
167 161
@@ -169,14 +163,14 @@ SKIP: {
169# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway 163# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway
170SKIP: { 164SKIP: {
171 skip "no non responsive host defined", 2 if ( ! $host_nonresponsive ); 165 skip "no non responsive host defined", 2 if ( ! $host_nonresponsive );
172 $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); 166 $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:");
173 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" ); 167 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" );
174 like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); 168 like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem");
175} 169}
176 170
177SKIP: { 171SKIP: {
178 skip "no non invalid host defined", 2 if ( ! $hostname_invalid ); 172 skip "no non invalid host defined", 2 if ( ! $hostname_invalid );
179 $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); 173 $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:");
180 cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" ); 174 cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" );
181 like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host)/', "String matches invalid host"); 175 like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host).*/s', "String matches invalid host");
182} 176}
diff --git a/plugins/t/check_ssh.t b/plugins/t/check_ssh.t
index 8008349..a5cd23c 100644
--- a/plugins/t/check_ssh.t
+++ b/plugins/t/check_ssh.t
@@ -9,17 +9,9 @@ use Test::More;
9use NPTest; 9use NPTest;
10 10
11# Required parameters 11# Required parameters
12my $ssh_host = getTestParameter("NP_SSH_HOST", 12my $ssh_host = getTestParameter("NP_SSH_HOST", "A host providing SSH service", "localhost");
13 "A host providing SSH service", 13my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1" );
14 "localhost"); 14my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost" );
15
16my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE",
17 "The hostname of system not responsive to network requests",
18 "10.0.0.1" );
19
20my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID",
21 "An invalid (not known to DNS) hostname",
22 "nosuchhost" );
23 15
24 16
25plan skip_all => "SSH_HOST must be defined" unless $ssh_host; 17plan skip_all => "SSH_HOST must be defined" unless $ssh_host;
diff --git a/plugins/t/check_swap.t b/plugins/t/check_swap.t
index e44adc9..de9e0f0 100644
--- a/plugins/t/check_swap.t
+++ b/plugins/t/check_swap.t
@@ -8,9 +8,9 @@ use strict;
8use Test::More tests => 8; 8use Test::More tests => 8;
9use NPTest; 9use NPTest;
10 10
11my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+ MB out of [0-9]+ MB\)/'; 11my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
12my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+ MB out of [0-9]+ MB\)/'; 12my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
13my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+ MB out of [0-9]+ MB\)/'; 13my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
14 14
15my $result; 15my $result;
16 16
diff --git a/plugins/t/check_tcp.t b/plugins/t/check_tcp.t
index 121b0cb..cb4de53 100644
--- a/plugins/t/check_tcp.t
+++ b/plugins/t/check_tcp.t
@@ -15,21 +15,11 @@ BEGIN {
15} 15}
16 16
17 17
18my $host_tcp_http = getTestParameter( "host_tcp_http", "NP_HOST_TCP_HTTP", "localhost", 18my $host_tcp_http = getTestParameter("NP_HOST_TCP_HTTP", "A host providing the HTTP Service (a web server)", "localhost");
19 "A host providing the HTTP Service (a web server)" ); 19my $host_tls_http = getTestParameter("NP_HOST_TLS_HTTP", "A host providing the HTTPS Service (a tls web server)", "localhost");
20 20my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
21my $host_tls_http = getTestParameter( "host_tls_http", "NP_HOST_TLS_HTTP", "localhost", 21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
22 "A host providing the HTTPS Service (a tls web server)" ); 22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
23
24my $host_nonresponsive = getTestParameter( "host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
25 "The hostname of system not responsive to network requests" );
26
27my $hostname_invalid = getTestParameter( "hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
28 "An invalid (not known to DNS) hostname" );
29
30my $internet_access = getTestParameter( "NP_INTERNET_ACCESS",
31 "Is this system directly connected to the internet?",
32 "yes");
33 23
34my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/'; 24my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/';
35 25
diff --git a/plugins/t/check_time.t b/plugins/t/check_time.t
index 961f56e..92c2f89 100644
--- a/plugins/t/check_time.t
+++ b/plugins/t/check_time.t
@@ -11,14 +11,9 @@ use NPTest;
11use vars qw($tests); 11use vars qw($tests);
12BEGIN {$tests = 8; plan tests => $tests} 12BEGIN {$tests = 8; plan tests => $tests}
13 13
14my $host_udp_time = getTestParameter( "host_udp_time", "NP_HOST_UDP_TIME", "localhost", 14my $host_udp_time = getTestParameter("NP_HOST_UDP_TIME", "A host providing the UDP Time Service", "localhost");
15 "A host providing the UDP Time Service" ); 15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
16 16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
17my $host_nonresponsive = getTestParameter( "host_nonresponsive", "NP_HOST_NONRESPONSIVE", "10.0.0.1",
18 "The hostname of system not responsive to network requests" );
19
20my $hostname_invalid = getTestParameter( "hostname_invalid", "NP_HOSTNAME_INVALID", "nosuchhost",
21 "An invalid (not known to DNS) hostname" );
22 17
23my $successOutput = '/^TIME OK - [0-9]+ second time difference/'; 18my $successOutput = '/^TIME OK - [0-9]+ second time difference/';
24 19
diff --git a/plugins/t/negate.t b/plugins/t/negate.t
index d96a109..5ec1c84 100644
--- a/plugins/t/negate.t
+++ b/plugins/t/negate.t
@@ -84,7 +84,7 @@ foreach my $current_state (keys(%state)) {
84 foreach my $new_state (keys(%state)) { 84 foreach my $new_state (keys(%state)) {
85 $res = NPTest->testCmd( "./negate -s --$current_state=$new_state ./check_dummy ".$state{$current_state}." 'Fake $new_state'" ); 85 $res = NPTest->testCmd( "./negate -s --$current_state=$new_state ./check_dummy ".$state{$current_state}." 'Fake $new_state'" );
86 is( $res->return_code, $state{$new_state}, "Got fake $new_state (with substitute)" ); 86 is( $res->return_code, $state{$new_state}, "Got fake $new_state (with substitute)" );
87 is( $res->output, uc($new_state).": Fake $new_state", "Substitued fake $new_state output"); 87 is( $res->output, uc($new_state).": Fake $new_state", "Substituted fake $new_state output");
88 } 88 }
89} 89}
90 90
diff --git a/plugins/tests/certs/.gitignore b/plugins/tests/certs/.gitignore
new file mode 100644
index 0000000..79acaaa
--- /dev/null
+++ b/plugins/tests/certs/.gitignore
@@ -0,0 +1,2 @@
1/*.csr
2/*.srl
diff --git a/plugins/tests/certs/client-cert.pem b/plugins/tests/certs/client-cert.pem
new file mode 100644
index 0000000..5709750
--- /dev/null
+++ b/plugins/tests/certs/client-cert.pem
@@ -0,0 +1,22 @@
1-----BEGIN CERTIFICATE-----
2MIIDtDCCApwCAQIwDQYJKoZIhvcNAQELBQAwgaAxCzAJBgNVBAYTAkRFMRAwDgYD
3VQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0b3Jp
4bmcgUGx1Z2luczEkMCIGA1UEAwwbTW9uaXRvcmluZyBQbHVnaW5zIENsaWVudENB
5MSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdpbnMub3JnMB4X
6DTIxMDIyODIxMDIxMloXDTMwMTEyODIxMDIxMlowgZ4xCzAJBgNVBAYTAkRFMRAw
7DgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0
8b3JpbmcgUGx1Z2luczEiMCAGA1UEAwwZTW9uaXRvcmluZyBQbHVnaW5zIENsaWVu
9dDErMCkGCSqGSIb3DQEJARYcZGV2ZWxAbW9uaXRvcmluZy1wbHVnaW5zLm9yZzCC
10ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM3EiqfFPomm5dZQPGYG5SrF
11rPvyqseXTzCkwUIUzGf+Sfm3s13zx7e3ije/04yKhTXgK59EQ793q7E2aWhSOz3s
12hwKKdylFkOIyc5jgbAfF1/pLZMK209rLt/mMRksXCRXYrHdTjRMx1ev4C2407+8Y
138qkf77DuYQmUqCQe7DPOvqLeagdw9JcLGmQNTKHg3fl6wyRl5K1Bsy+qXu2XvEjZ
140Ng7n8LHjOUkTqUEJndOxci9gL5cHU5ttul/GW34dKOtTuMU/pQX6/ywYusOGVOx
15RYI76OolRqj5BqbNctDIB/obe2RLo+UVx74/0jAxtH4XS23pYjO7NUpJcytsVG8C
16AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAYfaY5n4pCq0NWPCdeVVRr4nr+GAfv1TC
17/PKcGuEoJZKt7TQT+OOA5yeZMZb53OvtA49D1r9aoJzWe946KElWOEBqxDRi5Cdr
18wkqpwGcPT2RfAqA3/cvQZ1XsquboXrCf7ajdl5OC64bs2jkqCFh9gnxuI140g8Ar
19Njol8BFxRPaYWOnwuQwmh/2t0FJqr3WSD85HrNqtxUSNGbTdSsvCfgF0v7QVkvLG
203/cbx6z5hxzj2JUjhMnCvn+EbasoJt4xyBFvg67Q2229SMwu9YNqS63GVoKUqhCB
214Gl5v31qx8dAFKuRvnez3ze/6oohwmakZkst4hcQdgZocHhzesvKlg==
22-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/client-key.pem b/plugins/tests/certs/client-key.pem
new file mode 100644
index 0000000..09b6761
--- /dev/null
+++ b/plugins/tests/certs/client-key.pem
@@ -0,0 +1,28 @@
1-----BEGIN PRIVATE KEY-----
2MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNxIqnxT6JpuXW
3UDxmBuUqxaz78qrHl08wpMFCFMxn/kn5t7Nd88e3t4o3v9OMioU14CufREO/d6ux
4NmloUjs97IcCincpRZDiMnOY4GwHxdf6S2TCttPay7f5jEZLFwkV2Kx3U40TMdXr
5+AtuNO/vGPKpH++w7mEJlKgkHuwzzr6i3moHcPSXCxpkDUyh4N35esMkZeStQbMv
6ql7tl7xI2dDYO5/Cx4zlJE6lBCZ3TsXIvYC+XB1Obbbpfxlt+HSjrU7jFP6UF+v8
7sGLrDhlTsUWCO+jqJUao+QamzXLQyAf6G3tkS6PlFce+P9IwMbR+F0tt6WIzuzVK
8SXMrbFRvAgMBAAECggEBALtc2pB3p0E6KpAiEU0pvCRdSO1FgsIpAd+eNadRPur2
9fi+XWQkUwGeGBaJL1npja3aqP65PP40pj7nWfNaUAgOZyznCEU0QXiPJor6yo0vU
10l5v+aKpwRao107i0RRF80TYGTMx+1LeEqnCqNOZN56gERHlBbkTiWpOZvBzf1143
11oegTcyM6+Ee6+FYNhHaDyIYD0md1S2wGR+IBPet6HwWiakLNKahFPa7lOLIKfmmD
12iTtifcbf4724wSe44a0uTeP4JrquZSeIKakm8MEmffmYqpycnaakYefd0Xc5UEsH
13+VbhKpOWGY3d8FKHqUsTa+6QyXb2uFPo6A+yWm0pdJECgYEA7Prd5sbWACvXOcHT
14ONDBAgyfAVDQwOXi3D4dk6D5mg+/jxl5ZQY5slszJrwsLFtoEzXtYpNfTy3cpNOp
15JLbBDZYnqty+5tD8t3/Zv2IBXCAgvuk5CgfJWP5FNAfiyUEE6Vbp6J/5/vAnODsa
16fxZryN5UsH0X8ew7AlbfcVNyj4kCgYEA3khetIgn+GR6sv9jFRdCT6aJbp0xMsms
176F4v3L5FG4Kp+SwDHL1bVOhieJ5g8odYp9hDbgTEEqbJfNmyCOu9+OQmZ/mztku7
186reU8HhYBIvi+hFeJmvqKpdIgU0Zveg4Bst5QordmhPk8AHjBC4xvQ++uh7rwYKd
19WVsS08bGDjcCgYEAlAuNARUKsASzakOqHv5a9VrJIttH7povBYRQmd+gzxwzgcRa
20UEB5XvEWnYZE2lkoRYgVCtYiXqa6BsasDmGVbVV25okNQckhd8mJUMR7MQBpNJsi
21pR+EK/J9bSnYBf52gQdpDYiTdy60ca6KuQZaw5wRsEgV426+1pFK+dM16HECgYBY
22cTsdYb9lmbUoW201CxgbUQwFsw3MQ2pE2pT4o8wjcg3nUpe6a61XT08+5uV0Gl4w
23CmBp+gN52Fr7DjNEUWg5C64sWLIkqmWOspTUSU3cITyiex6W8wEtCRyUNfU0Fp2U
24Nol87HvXvmqtBFMraqXnr8gXjg4H5MxurUoEcWaEaQKBgCT4iIGZwW0Qf2rkFC7B
25xObzVGefivVVbaf8/c/LRO8TMLdnExkShMOmCzHeHV4mMEZDLbMOusHCI7xm10EX
26l3L1I1Kyqnhm1RH3e7TVWgkTmIDW3V5Fgrhm1jx5Iz6et4sb4Uh+bZq9tTLyqfZY
278s0yJUrfpjRggfk7eUs5s7aY
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/clientca-cert.pem b/plugins/tests/certs/clientca-cert.pem
new file mode 100644
index 0000000..9ce7cd7
--- /dev/null
+++ b/plugins/tests/certs/clientca-cert.pem
@@ -0,0 +1,25 @@
1-----BEGIN CERTIFICATE-----
2MIIEIzCCAwugAwIBAgIUL9Jfp5zv5B29NgDsNEFU2OM/UHswDQYJKoZIhvcNAQEL
3BQAwgaAxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZN
4dW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEkMCIGA1UEAwwbTW9u
5aXRvcmluZyBQbHVnaW5zIENsaWVudENBMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBt
6b25pdG9yaW5nLXBsdWdpbnMub3JnMB4XDTIxMDIyODIxMDIxMVoXDTMwMTEyODIx
7MDIxMVowgaAxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQH
8DAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEkMCIGA1UEAwwb
9TW9uaXRvcmluZyBQbHVnaW5zIENsaWVudENBMSswKQYJKoZIhvcNAQkBFhxkZXZl
10bEBtb25pdG9yaW5nLXBsdWdpbnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
11MIIBCgKCAQEAyxiWsGrsJFHw3VR0pqHviXUfbfKMw8LaCxI5EQZfInsMVkBIGWEW
12tFW6qDuAOsMdzsrKOnQRNNt852ts/0Uz++z8zysoauAGpc4JnCZuM5A1DU5CFXBx
13w6Ax+1ft3UsTt8C6kfLfs8mPCbtNVqAHrMrIqDxsNSRRxQSqkzp1vD8rwSKcbB1h
14u2+lut1bEqMe7dp89jKOtc6G/1tHUFQuLAGFoX/qk9yPscmQNzL6YbLP4m9r/416
15PsxWsAfyY97hmoYo6mSCue5LmeanOsjf4Kzq90hIJRwrpiUGmxGjW+tPLEhQBZw6
16C2wHyN74YIJYX2xREz2ijT0mgsqdhO5ZxwIDAQABo1MwUTAdBgNVHQ4EFgQUtsP9
17Z3fKkhmFp97Kh/cW/UqHMIMwHwYDVR0jBBgwFoAUtsP9Z3fKkhmFp97Kh/cW/UqH
18MIMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEApO5o+YECwTEv
19s+elDJZQ20UYwDSiU9Lpf4EcdnRv6FAb5UlhfRTH3ZdKCc/HX7kcKuy3PsF+b8Pw
20EusoKito9OlNEOF5HYAI9/J54/qceqn+SC0INsISeE19PvT0dma7lBSj4OvBv0IS
21GYbdztVaKLWqYgYs0mcEzteUc4MZcy1/C+Ru1i1Kp2s9/vIeAw2PV2+kpWtw88Pb
22FRJomGngP/hQdwniayCltG/Q1smS4iFEHNI5ayLZj1qJGMHwzqGiRr4KknJKfHzv
23fl4NQaFyMY31s1FRIS6QVIRFHVzUAlKZTdzwqEJygg3fUS9n9uDBnyDI/sW7DQuj
24yjSmYRS1hw==
25-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/clientca-key.pem b/plugins/tests/certs/clientca-key.pem
new file mode 100644
index 0000000..a939f03
--- /dev/null
+++ b/plugins/tests/certs/clientca-key.pem
@@ -0,0 +1,28 @@
1-----BEGIN PRIVATE KEY-----
2MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLGJawauwkUfDd
3VHSmoe+JdR9t8ozDwtoLEjkRBl8iewxWQEgZYRa0VbqoO4A6wx3Oyso6dBE023zn
4a2z/RTP77PzPKyhq4AalzgmcJm4zkDUNTkIVcHHDoDH7V+3dSxO3wLqR8t+zyY8J
5u01WoAesysioPGw1JFHFBKqTOnW8PyvBIpxsHWG7b6W63VsSox7t2nz2Mo61zob/
6W0dQVC4sAYWhf+qT3I+xyZA3Mvphss/ib2v/jXo+zFawB/Jj3uGahijqZIK57kuZ
75qc6yN/grOr3SEglHCumJQabEaNb608sSFAFnDoLbAfI3vhgglhfbFETPaKNPSaC
8yp2E7lnHAgMBAAECggEAJqAWiJbNMlsjI/Tb+pTxqYLM52wpuVFlhpWApOxBS517
9SywOikUcvE9RoI0wZfyVvq5yp4tLenID3z9fC21t5Yu8yOm8VhclLINy8G+epc/X
10RyCLEOjBuiLNXq/qXRvaNChDU16NjPPYcFFe9AqbaxFl+BkFu1Wc94tbpYSIv7Qt
11L6iBxUTXdgvLM5doa9AazIQzJx+jUsVCgRVQQf3zsLqtp9hH0Pfq+KWFIy5TA+bG
120NFmYyQndRjtT0ihWGuNU7D8AXa+z7abzk+HydIlx4D//vGgdNq92QYPdnu2BBya
135Fs6LkmkUonX/I8FbkLbRKkQWNPMt+Ks21t3xcVBgQKBgQDn4HuHVCPwxgU6Mv+5
140sHJXYBq1fDzrUt0+iTtYkRqViX+9Mp4sUpYgXext/wXFLcKzQQp5B0g1dLYLSRS
15KwhsdiN0J7ZcoP1GMStw8zsayRTf8C3WRU6aACqyFiylYbyh56XomfYgwhja/7l9
16pzpVJD9ecG+mLVAyAkJtK2JolQKBgQDgOZfvrQj0L4QG+9E5VmFc3PE+6k3g+zDO
17MWqTSh0fOHqdTEyet4bMC4DogXGVsvw0/UKwbrGHOk0+ltA5VyKUtK/whSutr/+S
18nhCHljhV0XUN/I3OFcvezFjM3g0oC4uy1cL30hoM4IfeHM1d3EYse9N1Y/Op+mR6
19Sx+fEku16wKBgQC0KQ7RjuZ95N2a4pUe5En9EtD8MU4Nhs/iC5k1d+yAUn8jIT9P
20lzCUo8NEKheMN2Qg2Dor8jlPkdNIc4qM7TKWUxQo49IlFlCzgPCnydRac3HsrMhw
21e1ke/pIt3FzEArR1d27I0xcRTL3TKm4M2ynPjWJPFj0peHue33KNL/A+IQKBgEpL
22awd0Sxo1wEZcG9gmwf32C01wbzuTn3lCsHB7Ryj4GtCR3nVclCJ50U24zjzu4Fhi
23bj1tgA8xhzSs3fOR5phlQkKsrWtQfJtFGm8CnEn7LBDlVMsrN7Dr/qRrEuro4HHy
24GDbq+8y2fO5glr955BqLMOadprf0imRnDeQ0OLffAoGBAJio+X+xpglgMOC4BeH9
259LcYi9nUEw8MDJNGo9/3e0XKA7spd3HShLDvt8YZhFJ2m168qBpGfezuw0+jpWxy
26PV9q0dokAgDx4pvCzIKaptZ1D30CWXJZHq25VK1tA41PCUIOh8JD5+R0MpxA5rn2
27DbqL4Vq7K7K0imGENYhHdyM+
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/clientchain-cert.pem b/plugins/tests/certs/clientchain-cert.pem
new file mode 100644
index 0000000..acd1e3e
--- /dev/null
+++ b/plugins/tests/certs/clientchain-cert.pem
@@ -0,0 +1,45 @@
1-----BEGIN CERTIFICATE-----
2MIIDuTCCAqECAQQwDQYJKoZIhvcNAQELBQAwgaAxCzAJBgNVBAYTAkRFMRAwDgYD
3VQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0b3Jp
4bmcgUGx1Z2luczEkMCIGA1UEAwwbTW9uaXRvcmluZyBQbHVnaW5zIENsaWVudENB
5MSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdpbnMub3JnMB4X
6DTIxMDIyODIxMDIxMloXDTMwMTEyODIxMDIxMlowgaMxCzAJBgNVBAYTAkRFMRAw
7DgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0
8b3JpbmcgUGx1Z2luczEnMCUGA1UEAwweTW9uaXRvcmluZyBQbHVnaW5zIENsaWVu
9dENoYWluMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdpbnMu
10b3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAphvoJBbi/rDvm3+X
118xok0sLCJvCRuUpSbU5wEmREQlkoOGmWK4l6r1JyOphKRBo8+n2MxPiCMvAmTrqx
12VlBmkcmyrwWj392Nga+2SLWTziASk5nFrrhV6U79PkgXnETV2Wk1/FNVIFkB8N+B
13undsTce8LLiCs7hfA5CK7ctJg8fqsAsmgKBNGzBRWwkbvxZPd6xlY6foIJeD7PQ2
14elvTmrD6WXSZq7GshFpDEkL3AifqrPMdsTnbBpyGgJ/fBM1b2dx9k53e25mgEQmn
15iSuYQxn08BsUT0FOvav8ksZLBQz859fuqCtwhikpODO635fD9zK5YkBPlVl+/5xo
16SvKOywIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBh4zeSKjENfY+VDLtPssaNQz2a
17R1ioY40lZ0WoihDSrfG32dqTK/R2YsLKBABjJ7uRYS1NIBMrtS2OktK8BWD5IUTF
18FuGuWilu6IWiTKZrLiZh1rsilNDVqwhorRPxDnbF+qVt9EMIvzKnKdJLGF+CWHN9
19yYJDeTD8MK5uR7zUJR3PsgW4ve5pFTi7z2UJ/xRvgOds6bmeeQnvaWDEL7k2+hrr
200G899A086NL3htzaOnIllg0xo2D1o4ToncAJn+cUQVJmHZSg9HYiD4Lg3z8uXPAl
21rt/MX7dBm4dnImLXbSg7N3e8FdUtz+kZT9z+beKAeIe9JTbpxtsVUTzUZBBA
22-----END CERTIFICATE-----
23-----BEGIN CERTIFICATE-----
24MIID2jCCAsKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBoDELMAkGA1UEBhMCREUx
25EDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwSTW9u
26aXRvcmluZyBQbHVnaW5zMSQwIgYDVQQDDBtNb25pdG9yaW5nIFBsdWdpbnMgQ2xp
27ZW50Q0ExKzApBgkqhkiG9w0BCQEWHGRldmVsQG1vbml0b3JpbmctcGx1Z2lucy5v
28cmcwHhcNMjEwMjI4MjEwMjEyWhcNMzAxMTI4MjEwMjEyWjCBqjELMAkGA1UEBhMC
29REUxEDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwS
30TW9uaXRvcmluZyBQbHVnaW5zMS4wLAYDVQQDDCVNb25pdG9yaW5nIFBsdWdpbnMg
31Q2xpZW50SW50ZXJtZWRpYXRlMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9y
32aW5nLXBsdWdpbnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
336rUgOZ9pAOxrcgeeOT3Vmu1YmY2O/C9tXhpKzDzjTaWUzcdDg00KdsjXfgbDzSiV
34uvMzjX63aKpmqeFG+05D2VzQGit3knqerUgl10FnTotiJGF5CU5/gY1aPxTJ7rj2
35tD6LINBkJcPTyQ4MoJT19pssvCax9erY1RxoXxLblJ+31C+VvrftdmBP4nVKXK26
364anb1oUQhkgpXpJimJBmF+v7NbDs1Wh21Be80KXUh9SKgePhSQblr2QlRcA7jLgJ
374PMjZ+KYF+da+4RB7s+DvTXVDMn9AL84E1w5Ut1E8XZV+u4RjWPvNdhK/7GnuxOR
38C9SdxonqkPQ8hiI7thP9bQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
39SIb3DQEBCwUAA4IBAQDKQeiDbyr0/7sEhX33MmTDv84GeWgKl9qqHecx+d/0vImb
40c8XHK0PDa4lVqo/BW4P1hjKzpt2DW35kbOhuqGqM0lasIczef43aCDDEBLwstAe6
41qMoyWGVGoAQbpwT3li2pMrsIYoPwMvoSGNUphjrkdpviff2POkLly7a5RrR1X3qt
42Dai6eYbeMCr9NdgW7AZ5++/sKlFoe+zVk/Ed31s4D2lh3awrApZhVgcoquPmEwpt
43gm+OgRmHw50U4SF3ZaJPwDyLMbx+clH/bgUg0+Za9e53Br1NtGKmw7hh/7CG/hy0
44yxeLd930pH4vZu7s0XM56N/ckkfUzRkAH8dSmhH4
45-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/clientchain-key.pem b/plugins/tests/certs/clientchain-key.pem
new file mode 100644
index 0000000..0263604
--- /dev/null
+++ b/plugins/tests/certs/clientchain-key.pem
@@ -0,0 +1,28 @@
1-----BEGIN PRIVATE KEY-----
2MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmG+gkFuL+sO+b
3f5fzGiTSwsIm8JG5SlJtTnASZERCWSg4aZYriXqvUnI6mEpEGjz6fYzE+IIy8CZO
4urFWUGaRybKvBaPf3Y2Br7ZItZPOIBKTmcWuuFXpTv0+SBecRNXZaTX8U1UgWQHw
534G6d2xNx7wsuIKzuF8DkIrty0mDx+qwCyaAoE0bMFFbCRu/Fk93rGVjp+ggl4Ps
69DZ6W9OasPpZdJmrsayEWkMSQvcCJ+qs8x2xOdsGnIaAn98EzVvZ3H2Tnd7bmaAR
7CaeJK5hDGfTwGxRPQU69q/ySxksFDPzn1+6oK3CGKSk4M7rfl8P3MrliQE+VWX7/
8nGhK8o7LAgMBAAECggEAAfTqMyKh4eYrrGVAYPi53lG0/8htrwUVG3yFDXJo628p
9biCwSCsCavZJqi8JEOxOM5UvB1L2FauGh/7i/+VKkAUUOcOTPpvZguGTACBDcXYn
10Qd3Z2kkJmgn4Kbenr4uQCVOX8zT4F710rGW1nYCyoefsa4pw37UYSW52dH6kiwzW
119k4X251nDMl/twBdOcjZbL768IEa5l4nySLpUNwfrVbSb1NzBoH0dVioh3DTLjt6
12gaShW4eIpaKczht1U97n6/7WNLl6vHX/mR99k/py8OhzhR1ccYpd2IfSHAWyQT0M
13K8BoNnkjICrr9oc0FCr2BVJa3IzKHlhukF4GTZiGYQKBgQDWCHTwAmwL4FFEBVhj
14pZne/sjaZc8TzPPxA8SkmxwDIZrM7tSu7qUuYgWTM432jZbLILWTyGfXf2PpqyF6
15wOpoBJj1ETkre8ZfRmYvsSvS5vtjF3Drszol+XvZnOclfB5VG3m5P2vYkQ8wI9OE
16Y5jUBgDj0RsCNd8QnrC1u54U/wKBgQDGrd5y8S9kUT0P0lkZit7bYjSPJExtClXt
17V7YNTjELrVCdc0jranxBWaub8NP3e6TGTi9HiQWvk2eOAS2qyccqlK4+YAK5XO3D
18EpFUNNcClq8CErw2POuCAKajrPuSp6vd6q8h4lTzDExVctQS4R9fRKKFBKkPUV5G
19UiKFllnKNQKBgQDBGIQXfLfpxwjKK2BhFihKDOc8UhmOrZtvV4zzTJTrJkg4l0f+
20QoN34ytQcHSleXwP6oSmvWkh/GYxjBj6XE2eZndwsYc4ecSwdB0A7gCxl345Gg7g
21NqRBWmGoJGxNXzsmYVFiFZvAmK5xKgFMMWbR8lCfOCn7xopmviSC8K9gFQKBgFRb
22KmH/SbH8VELNews/TVQ0pEBKlzCM/OLjJOcNVgGxOtM/Say677sHibeST0168AFK
233QQwh3t+yK8gjPVA6xGHQ1w0g7OUY1c6IP5x2QC+XdwxfDxDLXNrN1WzcrVX/78f
24j/CBGrR/ekGlmanSb/GRQLfdvLJGSBLveLzjk4gpAoGBANN9RUm/aRz3dDBWex46
25kJ15xKJfLZiUeyDvY5+5d7YF4/tw5LU4XmKQNhiojHecykrTzPUMaGyMrbMPNn32
26WFW9CKMjuBEwWpMDJJb1/5NLEvpwu++sr7bUPZkQl76ot6OqgNHodbP8ATqrNr80
275b8FrEN1LyfkTbabxNyAWcA0
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/clientintermediate-cert.pem b/plugins/tests/certs/clientintermediate-cert.pem
new file mode 100644
index 0000000..608a8fa
--- /dev/null
+++ b/plugins/tests/certs/clientintermediate-cert.pem
@@ -0,0 +1,23 @@
1-----BEGIN CERTIFICATE-----
2MIID2jCCAsKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBoDELMAkGA1UEBhMCREUx
3EDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwSTW9u
4aXRvcmluZyBQbHVnaW5zMSQwIgYDVQQDDBtNb25pdG9yaW5nIFBsdWdpbnMgQ2xp
5ZW50Q0ExKzApBgkqhkiG9w0BCQEWHGRldmVsQG1vbml0b3JpbmctcGx1Z2lucy5v
6cmcwHhcNMjEwMjI4MjEwMjEyWhcNMzAxMTI4MjEwMjEyWjCBqjELMAkGA1UEBhMC
7REUxEDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwS
8TW9uaXRvcmluZyBQbHVnaW5zMS4wLAYDVQQDDCVNb25pdG9yaW5nIFBsdWdpbnMg
9Q2xpZW50SW50ZXJtZWRpYXRlMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9y
10aW5nLXBsdWdpbnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
116rUgOZ9pAOxrcgeeOT3Vmu1YmY2O/C9tXhpKzDzjTaWUzcdDg00KdsjXfgbDzSiV
12uvMzjX63aKpmqeFG+05D2VzQGit3knqerUgl10FnTotiJGF5CU5/gY1aPxTJ7rj2
13tD6LINBkJcPTyQ4MoJT19pssvCax9erY1RxoXxLblJ+31C+VvrftdmBP4nVKXK26
144anb1oUQhkgpXpJimJBmF+v7NbDs1Wh21Be80KXUh9SKgePhSQblr2QlRcA7jLgJ
154PMjZ+KYF+da+4RB7s+DvTXVDMn9AL84E1w5Ut1E8XZV+u4RjWPvNdhK/7GnuxOR
16C9SdxonqkPQ8hiI7thP9bQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
17SIb3DQEBCwUAA4IBAQDKQeiDbyr0/7sEhX33MmTDv84GeWgKl9qqHecx+d/0vImb
18c8XHK0PDa4lVqo/BW4P1hjKzpt2DW35kbOhuqGqM0lasIczef43aCDDEBLwstAe6
19qMoyWGVGoAQbpwT3li2pMrsIYoPwMvoSGNUphjrkdpviff2POkLly7a5RrR1X3qt
20Dai6eYbeMCr9NdgW7AZ5++/sKlFoe+zVk/Ed31s4D2lh3awrApZhVgcoquPmEwpt
21gm+OgRmHw50U4SF3ZaJPwDyLMbx+clH/bgUg0+Za9e53Br1NtGKmw7hh/7CG/hy0
22yxeLd930pH4vZu7s0XM56N/ckkfUzRkAH8dSmhH4
23-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/clientintermediate-key.pem b/plugins/tests/certs/clientintermediate-key.pem
new file mode 100644
index 0000000..13f6887
--- /dev/null
+++ b/plugins/tests/certs/clientintermediate-key.pem
@@ -0,0 +1,28 @@
1-----BEGIN PRIVATE KEY-----
2MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDqtSA5n2kA7Gty
3B545PdWa7ViZjY78L21eGkrMPONNpZTNx0ODTQp2yNd+BsPNKJW68zONfrdoqmap
44Ub7TkPZXNAaK3eSep6tSCXXQWdOi2IkYXkJTn+BjVo/FMnuuPa0Posg0GQlw9PJ
5DgyglPX2myy8JrH16tjVHGhfEtuUn7fUL5W+t+12YE/idUpcrbrhqdvWhRCGSCle
6kmKYkGYX6/s1sOzVaHbUF7zQpdSH1IqB4+FJBuWvZCVFwDuMuAng8yNn4pgX51r7
7hEHuz4O9NdUMyf0AvzgTXDlS3UTxdlX67hGNY+812Er/sae7E5EL1J3GieqQ9DyG
8Iju2E/1tAgMBAAECggEACyYJXtNUoIeaXvM/r8ZhJBfMEpcnyJDUKBklnmfyABky
9ZUfmzBDXw2as3b6ihFc+LYAp3bm8KouVjtI1lfBUxrli5StVZa7PZLm9mmjv6Eo0
10ojfDEQ8afWPieoaZRO6iQVOLNkbPyv9vSuiQ7vvEZy9dw54u69h47j6IMqPprDiG
11ropUNeGAvTnh1Vf9/8aCHEvHUNHcc4zjzGiQ+E60JgnbpGVeJKoeiMgrQE0yjweo
12KyKA47Y6vqP6+AxAaPplXtmrx2UCbMjktHNvLvg42+2UlLS5roiwmJYEN9c6iT6t
13y82MJrjEFGZyLG2u6ZQANSJiIWaCnOyT1o2deJ8NoQKBgQD7UxivDTuljQD0so+E
14JX9UaFZ9PgS+8LC9v56PciL4XQ7bcCVP5vVgZZPABiQ9i989Wq7qI042Jrfu5qtE
15SthlOAu80GvAQV+Oujwo7ZzM6ciQtjMsj63r2uayWXnmQ07QcIg7x7y161Pt9Bqr
16LIDrqHziIj/lzT7+6QKZaQwFaQKBgQDvEuSC14CBlMhy2jji71kB/3Ya3c+8dP+A
17kQZL9wEWK4a4dm8IaTS8jl1/luhQUzFRMyh2rWaTqqigSe3dvs5DRblhE5NPwTSI
189TO7t1EnzjW3R8LxZZsySyiSFnZ/8mR0empxq0Mov37OdXBj0tXuuzREf/hwijWh
19WuLxJUSjZQKBgAIDZ2Y3l+u6lnBfYdDwL/XwJAk6zvTsnq3WdCG4C1mr/St62YGr
20WvnbtnRKWE356d7m9BHCGKVMaBrM1EBmzRb6fPWVQde3blmJWmQFi0UE9mtaWkyY
21Fg+WoFR7bQOQNHhs/lpkPjnC2dhFJVWLtLiuj9mL5rEjlMab/T5XXhZJAoGBAMEP
22FZ8fXbPGrTQqSwPfWpZFcF9zvbynEmkFM/uGRMddcNZnNXSqWJ7nrFNLTuEGvW2g
23DU4A6zPV/YQrDz4hRjmHBZOCFlSyZbUvpY4yFAQ7/p66AY+kiHZNwT5vi1P5Luvs
24qyaNsZcnRMR+i7rg2EeHv0aNvNdMlNBvL5KikNINAoGAU2P/phdwJOUcqgHavQcQ
25ureTEyZ5i5AeNomNeHSj0slG24V9nxOqEL7D00JKln7oAPovYBUWocEnF39uBJe0
26p0Hy7fCCK6EI8/0QyiQuuZmJfDEEvjQqE6irONNH63r2UwDEpDNGFvGsZNuWHLZc
27SXADu5oSNu6o6IydiyOx528=
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/expired-cert.pem b/plugins/tests/certs/expired-cert.pem
index 40324cf..87fc8e4 100644
--- a/plugins/tests/certs/expired-cert.pem
+++ b/plugins/tests/certs/expired-cert.pem
@@ -1,21 +1,24 @@
1-----BEGIN CERTIFICATE----- 1-----BEGIN CERTIFICATE-----
2MIIDYzCCAsygAwIBAgIJAJISzcX71f5pMA0GCSqGSIb3DQEBBAUAMH8xCzAJBgNV 2MIIEETCCAvmgAwIBAgIUVDKkhcUoYFnjYCw12tScPIqQzqIwDQYJKoZIhvcNAQEL
3BAYTAlVLMRMwEQYDVQQIEwpEZXJieXNoaXJlMQ8wDQYDVQQHEwZCZWxwZXIxFzAV 3BQAwgZcxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZN
4BgNVBAoTDk5hZ2lvcyBQbHVnaW5zMREwDwYDVQQDEwhUb24gVm9vbjEeMBwGCSqG 4dW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9u
5SIb3DQEJARYPdG9udm9vbkBtYWMuY29tMB4XDTA5MDMwNjAwMTMxNVoXDTA5MDMw 5aXRvcmluZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5n
6NTAwMTMxNlowfzELMAkGA1UEBhMCVUsxEzARBgNVBAgTCkRlcmJ5c2hpcmUxDzAN 6LXBsdWdpbnMub3JnMB4XDTA4MDEwMTEyMDAwMFoXDTA4MDEwMjEyMDAwMFowgZcx
7BgNVBAcTBkJlbHBlcjEXMBUGA1UEChMOTmFnaW9zIFBsdWdpbnMxETAPBgNVBAMT 7CzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gx
8CFRvbiBWb29uMR4wHAYJKoZIhvcNAQkBFg90b252b29uQG1hYy5jb20wgZ8wDQYJ 8GzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9uaXRvcmlu
9KoZIhvcNAQEBBQADgY0AMIGJAoGBAOQHP4JnzACi4q6quXAiK+gTSffG6yyjEV+K 9ZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdp
10iyutRgBF2MdF03X5ls0wENw/5fnMTrHynl4XoGoV/rD4CR2hGT0m7dv7Vu0MRLlP 10bnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwg1dmGT3rVqM
11J1SCiFeMuQS30zzLMJr0A7IW869qRlKQmzxs1JT6XDbSoNQuF154zoxwNsKlMjoX 11beVWWLy8EAiq9re07AF8sTERy9oIYF5EUq9f0xO53mwwqIWV77O9mF99/kDFGQuQ
12tJSHN2YpAgMBAAGjgeYwgeMwHQYDVR0OBBYEFHWjM9OQldrDLMcAfPnUVfGxlzOp 12NOnICMSHXNtMXEXzfBaMighw0uyCh1o/VCejNQ5x/HU8aLh930g5DIcOJQ3fZ4v9
13MIGzBgNVHSMEgaswgaiAFHWjM9OQldrDLMcAfPnUVfGxlzOpoYGEpIGBMH8xCzAJ 138kBaie7+aPgRMVDM1vIrILfedq9Kt56zvPizkXhDeqxjKyIZdrdoBlX5zAfftWtY
14BgNVBAYTAlVLMRMwEQYDVQQIEwpEZXJieXNoaXJlMQ8wDQYDVQQHEwZCZWxwZXIx 14HpQ+lkThSSXqQnchN6S2JFejmRtsNnceDVOBBdvlzmH0NlfwjynLK3/EJooTsINy
15FzAVBgNVBAoTDk5hZ2lvcyBQbHVnaW5zMREwDwYDVQQDEwhUb24gVm9vbjEeMBwG 15i9dXD8/Oe8r+UA+nokWvnWC2IAUJjpxW+XAyTG/NofGwX+PwquT0YD5cSlODIwZA
16CSqGSIb3DQEJARYPdG9udm9vbkBtYWMuY29tggkAkhLNxfvV/mkwDAYDVR0TBAUw 16WAimygWLqQIDAQABo1MwUTAdBgNVHQ4EFgQUsKyJAwR9OXWEcSZMQz73GfpxCJIw
17AwEB/zANBgkqhkiG9w0BAQQFAAOBgQDHjoXoGwBamCiNplTt93jH/TO08RATdZP5 17HwYDVR0jBBgwFoAUsKyJAwR9OXWEcSZMQz73GfpxCJIwDwYDVR0TAQH/BAUwAwEB
1845hlxv2+PKCjjTiFa2mjAvopFiqmYsr40XYEmpeYMiaOzOW5rBjtqBAT/JJWyfda 18/zANBgkqhkiG9w0BAQsFAAOCAQEAYKFGX7J3Fc/T9s278w61E2dSsY4DS/mjSDik
19SCmj3swqyKus63rv/iuokIhZzBdhbB+eOJJrmwT2SEc5KdRaipH0QAGF1nZAAGzo 19fMWvod6eKw0fE3wJOnkWxjEH3VywTY6CmHd/oiJOaD8lr/Vk+BJfYNVBaVNmguyg
206xW7hkzYog== 204LXoWz9Benx0bAIeuDbNAhOvA4H4aIz8UrD9lKFvKdRp42gPMLtMEbzbLcBdT95D
216BX7EhYm7vTnpitLPgFxVCsJ1JFqv2AQfUm+IkqQkezPs5x0tWLyrvCDNRGJ0kfv
22UuowpUZXDOh3k1vB+xaSOFviieLaCW8TSdd5FZgI2HQj4e6vCKsMGuKKZXrMUTI/
23qtrFlUfsOuwourfC5LMHtCyYo5B3uvAWT1eTXxhrGqyleSlxJQ==
21-----END CERTIFICATE----- 24-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/expired-key.pem b/plugins/tests/certs/expired-key.pem
index af0e24d..c5bba56 100644
--- a/plugins/tests/certs/expired-key.pem
+++ b/plugins/tests/certs/expired-key.pem
@@ -1,15 +1,28 @@
1-----BEGIN RSA PRIVATE KEY----- 1-----BEGIN PRIVATE KEY-----
2MIICXAIBAAKBgQDkBz+CZ8wAouKuqrlwIivoE0n3xussoxFfiosrrUYARdjHRdN1 2MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDCDV2YZPetWoxt
3+ZbNMBDcP+X5zE6x8p5eF6BqFf6w+AkdoRk9Ju3b+1btDES5TydUgohXjLkEt9M8 35VZYvLwQCKr2t7TsAXyxMRHL2ghgXkRSr1/TE7nebDCohZXvs72YX33+QMUZC5A0
4yzCa9AOyFvOvakZSkJs8bNSU+lw20qDULhdeeM6McDbCpTI6F7SUhzdmKQIDAQAB 46cgIxIdc20xcRfN8FoyKCHDS7IKHWj9UJ6M1DnH8dTxouH3fSDkMhw4lDd9ni/3y
5AoGARgI3rHjjuDpKMGg4IMZNBqaNaiZHY9/44IVvrww21rSbFqtIfgsQEpU0R/rS 5QFqJ7v5o+BExUMzW8isgt952r0q3nrO8+LOReEN6rGMrIhl2t2gGVfnMB9+1a1ge
6R7xDWPztRGQqmwd/t6OfYNpqHbjO1MWzasVBVnzue5P59Y1xy1h0LZF8+a9GY++0 6lD6WROFJJepCdyE3pLYkV6OZG2w2dx4NU4EF2+XOYfQ2V/CPKcsrf8QmihOwg3KL
7uAGUC24jsXSmypNVzoX+ZKyinA3oYV/etdPYx1W8Ms5XIzUCQQD7xwhMuLok6Kbq 711cPz857yv5QD6eiRa+dYLYgBQmOnFb5cDJMb82h8bBf4/Cq5PRgPlxKU4MjBkBY
8UEgiSfBTbx+haP3IiqqMF14z8QoEyD3jchydNaXEYdQxN8jEl2aPrMqTc6x8Jq4/ 8CKbKBYupAgMBAAECggEBAJ2mdCKJ7LoWdT4W8pZ3BqZUFGkKCF8wOhhOUDH3+ZQp
9ai0OkB+fAkEA59pAmN81HylV7+CsVjLOSbJqzau7NDxSs2uutxhHZRwz0e25wVer 9IYK3XbdDMF7mMIXIuW4a7W4sLlTwU/Ar98U1JMESwRIMS7YvUke+ngDKKLcDVGwY
10fA03l08u0ebC/TDHkmHV6ikCryM5HU2FNwJAVZJFzd2S1myEHmr+uTisB49jDrbi 10Qpjg9vP0v2Al8qT1NbW/nDF0S2aJJbWfAvnblHK5ClFHL9iL107NQYJ8PqzXbnFL
11WkBWypo+mCS6JPnxntXvx7auClq9haTSBY73eqldiFPuMZvr6P2rJqHxPQJBAOTM 11gCQRiZxVHlrbn/73ZUMHPGEoU0711U9hSjrsqrRuSAMC+V38s4HxOomZWutlVAHF
12quaxjti7kATy8N73sD9mBKQGju1TgkFxSK+DFCGhnTnToXY9MAtxd6SoDYoyccYu 12HwClNZBqRO+a2njPyUuV9DM/rl5Tm9IQ89iFo3/QEORICK77HjJYhi+UzdfI5F35
13dyPrzJAR/IYc+mYCdC0CQDKlZuMPVXEgvGaQapzMQ++5yJRvMZF4tWvONBs0OCE9 13UntRJt+WLaiAP+K6Vt6oxHSm58qXnOkeLzaAunTTie0CgYEA6OLYfme8xe5zYXWX
14QYarsTi5M20cymMBXHOLZIjqwsni4G/C9kqJSvC75Vg= 14rqmKNYdcVfMkvL+vUfVT475o/piRtE54JC1LYWEFAN8paxEWHD5HZMy0+ONNXfGm
15-----END RSA PRIVATE KEY----- 15zyNNTN/Lagz4WcpdFzKQmhfdro7DzRiDfdvwSLmaZDyE41PPPVVvfrI9IeDiUNY4
16nWLSb3sWo96Iuns+RoMqeA9wkqsCgYEA1U/UqeVQVTPlrWyiB2VXoI1xvFCCJTf8
174NC0gcisxLRrtINk0BwrUJrRy0x1OLpJWiKwUl/W1GgvPPfhbYcUOb669JNtTIjY
18FeIZblCTjz9GzKKmXeDciXvccyEdCJVUlPO3/e2JiJ4mCDjULprifq0a2gcQevFS
19PfqVULhBOvsCgYB5KfS7J1vGmv36ucSWAe0/VlKLATqe3RfpCzt/JQTZWSWNaroF
20EG/ElUaWIoUZCEW5oglg/0Q0rYYGF4DTCingkhrx7ReVF70BIbSsBzi15d8nKNbY
21t4I3RCF4fyggYe1TmsysXS2DH85/gkToVY7oo2CvF0uJwi8vXnTNDDNkiwKBgHKs
22mAc94BHt9GtnGzQepx0I7TvvjAe2MZwqlt+uojKdS8mfWXMHscGDeYVxdRMqEoUC
23YQfnvfYyjDKaj/XxyE3C237gQsICTyh0hHdpmepIeidIyWdumyDOFZVPF+ylWvM4
24kpFQQb/QRWHmKyti2KCBLw5G/fUaBryLGfprE6ZBAoGBANy5rr41A679UQZ0abev
25bOZb7YWOHYp/wReJaQbvLAyR30os3aEY/0ht9S+OWdrgGMezPKvsx2Sqr/CwoFXI
26esiklpknr11maEPxnQJYi4FYiXS1a3NCg7yBvKzFEgx2XnMAC3s6zhuZXaFq4zNu
27pm5Btrq/NZqtVXovS+UhGLvJ
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/ext.cnf b/plugins/tests/certs/ext.cnf
new file mode 100644
index 0000000..d09cee1
--- /dev/null
+++ b/plugins/tests/certs/ext.cnf
@@ -0,0 +1,2 @@
1[ client_ca ]
2basicConstraints = critical, CA:true
diff --git a/plugins/tests/certs/generate-certs.sh b/plugins/tests/certs/generate-certs.sh
new file mode 100755
index 0000000..78660a2
--- /dev/null
+++ b/plugins/tests/certs/generate-certs.sh
@@ -0,0 +1,63 @@
1#!/bin/sh -e
2#
3# Recreates the https server certificates
4#
5# Set the GEN_EXPIRED environment variable to also regenerate
6# the expired certificate.
7
8cd "$(dirname "$0")"
9trap 'rm -f *.csr; rm -f clientca-cert.srl' EXIT
10
11subj() {
12 c="DE"
13 st="Bavaria"
14 l="Munich"
15 o="Monitoring Plugins"
16 cn="Monitoring Plugins"
17 emailAddress="devel@monitoring-plugins.org"
18
19 if [ -n "$1" ]; then
20 # Add to CN
21 cn="$cn $1"
22 fi
23
24 printf "/C=%s/ST=%s/L=%s/O=%s/CN=%s/emailAddress=%s" \
25 "$c" "$st" "$l" "$o" "$cn" "$emailAddress"
26}
27
28# server
29openssl req -new -x509 -days 3560 -nodes \
30 -keyout server-key.pem -out server-cert.pem \
31 -subj "$(subj)"
32# server, expired
33# there is generally no need to regenerate this, as it will stay epxired
34[ -n "$GEN_EXPIRED" ] && TZ=UTC faketime -f '2008-01-01 12:00:00' \
35 openssl req -new -x509 -days 1 -nodes \
36 -keyout expired-key.pem -out expired-cert.pem \
37 -subj "$(subj)"
38
39# client, ca
40openssl req -new -x509 -days 3560 -nodes \
41 -keyout clientca-key.pem -out clientca-cert.pem \
42 -subj "$(subj ClientCA)"
43echo "01" >clientca-cert.srl
44# client
45openssl req -new -nodes \
46 -keyout client-key.pem -out client-cert.csr \
47 -subj "$(subj Client)"
48openssl x509 -days 3560 -req -CA clientca-cert.pem -CAkey clientca-key.pem \
49 -in client-cert.csr -out client-cert.pem
50# client, intermediate
51openssl req -new -nodes \
52 -keyout clientintermediate-key.pem -out clientintermediate-cert.csr \
53 -subj "$(subj ClientIntermediate)"
54openssl x509 -days 3560 -req -CA clientca-cert.pem -CAkey clientca-key.pem \
55 -extfile ext.cnf -extensions client_ca \
56 -in clientintermediate-cert.csr -out clientintermediate-cert.pem
57# client, chain
58openssl req -new -nodes \
59 -keyout clientchain-key.pem -out clientchain-cert.csr \
60 -subj "$(subj ClientChain)"
61openssl x509 -days 3560 -req -CA clientca-cert.pem -CAkey clientca-key.pem \
62 -in clientchain-cert.csr -out clientchain-cert.pem
63cat clientintermediate-cert.pem >>clientchain-cert.pem
diff --git a/plugins/tests/certs/server-cert.pem b/plugins/tests/certs/server-cert.pem
index 549e4f7..d1249ef 100644
--- a/plugins/tests/certs/server-cert.pem
+++ b/plugins/tests/certs/server-cert.pem
@@ -1,21 +1,24 @@
1-----BEGIN CERTIFICATE----- 1-----BEGIN CERTIFICATE-----
2MIIDYzCCAsygAwIBAgIJAL8LkpNwzYdxMA0GCSqGSIb3DQEBBAUAMH8xCzAJBgNV 2MIIEETCCAvmgAwIBAgIUZwOhY4myaCUaPek3NM+MxbLG9vwwDQYJKoZIhvcNAQEL
3BAYTAlVLMRMwEQYDVQQIEwpEZXJieXNoaXJlMQ8wDQYDVQQHEwZCZWxwZXIxFzAV 3BQAwgZcxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZN
4BgNVBAoTDk5hZ2lvcyBQbHVnaW5zMREwDwYDVQQDEwhUb24gVm9vbjEeMBwGCSqG 4dW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9u
5SIb3DQEJARYPdG9udm9vbkBtYWMuY29tMB4XDTA5MDMwNTIxNDEyOFoXDTE5MDMw 5aXRvcmluZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5n
6MzIxNDEyOFowfzELMAkGA1UEBhMCVUsxEzARBgNVBAgTCkRlcmJ5c2hpcmUxDzAN 6LXBsdWdpbnMub3JnMB4XDTIxMDIyODIxMDIxMVoXDTMwMTEyODIxMDIxMVowgZcx
7BgNVBAcTBkJlbHBlcjEXMBUGA1UEChMOTmFnaW9zIFBsdWdpbnMxETAPBgNVBAMT 7CzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gx
8CFRvbiBWb29uMR4wHAYJKoZIhvcNAQkBFg90b252b29uQG1hYy5jb20wgZ8wDQYJ 8GzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9uaXRvcmlu
9KoZIhvcNAQEBBQADgY0AMIGJAoGBAKcWMBtNtfY8vZXk0SN6/EYTVN/LOvaOSegy 9ZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdp
10oVdLoGwuwjagk+XmCzvCqHZRp8lnCLay7AO8AQI7TSN02ihCcSrgGA9OT+HciIJ1 10bnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/3eBA4WG6xz
11l5/kEYUAuA1PR6YKK/T713zUAlMzy2tsugx5+xSsSEwsXkmne52jJiG/wuE5CLT0 11LfM6xcWywxThb1Rp7XAW3ewQd9/PdoWXEe8BJWlLfyYi1drLMcsDywhLkKmW4Vp9
129pF8HQqHAgMBAAGjgeYwgeMwHQYDVR0OBBYEFGioSPQ/rdE19+zaeY2YvHTXlUDI 121R4PAkiljjrB/ZaUMDLJ1ri3dwX4RvXG7crsU3QWFWCBOrf5V2FTRQ2m/H/KyB/6
13MIGzBgNVHSMEgaswgaiAFGioSPQ/rdE19+zaeY2YvHTXlUDIoYGEpIGBMH8xCzAJ 13rVZANsU47HqTFSPiUm2j7P3wx/wtHeYC+qmNG7zZTjAYPYxfKiod0lytTSmb+h54
14BgNVBAYTAlVLMRMwEQYDVQQIEwpEZXJieXNoaXJlMQ8wDQYDVQQHEwZCZWxwZXIx 146lxn3+VPEXZAQZlLvPnm/58JnXGrUv7B2yocf5MhKkLJOrGxH2hfwKISfaj2gpOV
15FzAVBgNVBAoTDk5hZ2lvcyBQbHVnaW5zMREwDwYDVQQDEwhUb24gVm9vbjEeMBwG 15m4PUVYiDzCSpq1fPvwbUxIvdO27xprx+mrGOFM6f2UCEOc35w8FSmYiR2yQTnEJK
16CSqGSIb3DQEJARYPdG9udm9vbkBtYWMuY29tggkAvwuSk3DNh3EwDAYDVR0TBAUw 16pbSQD6t1jQIDAQABo1MwUTAdBgNVHQ4EFgQUMeYgglT2aWDlF8KEeF2376AlTGYw
17AwEB/zANBgkqhkiG9w0BAQQFAAOBgQCdqasaIO6JiV5ONFG6Tr1++85UfEdZKMUX 17HwYDVR0jBBgwFoAUMeYgglT2aWDlF8KEeF2376AlTGYwDwYDVR0TAQH/BAUwAwEB
18N2NHiNNUunolIZEYR+dW99ezKmHlDiQ/tMgoLVYpl2Ubho2pAkLGQR+W0ZASgWQ1 18/zANBgkqhkiG9w0BAQsFAAOCAQEAFcEg83rTJdgkp7JLYqK0j8JogSHNlDYchr/r
19NjfV27Rv0y6lYQMTA0lVAU93L1x9reo3FMedmL5+H+lIEpLCxEPtAJNISrJOneZB 19VxKBgQwfnjSp5A8d5+uTQ9s3QDabw8v7YeSrzYXbbjuWZ61mnl84tzOQ8LMeESnC
20W5jDadwkoQ== 20CBXRCxB8Ow22WsVTVJq279SGYT+cZrdsmqGVWDi1A0C5kH+XTLAioG5CZmmxemD/
21S92ZoRxGyYfg33r+3X6EMcEYtHKGxCUa3EPcPOL4dq2F3nOnyjiWPZm3786H3NY2
22nsYwrEhAdUFtbYSsV5O0c/Zlc33fmTfh654ab35io1DtwmFo7q8J532dUE007EN0
23mIQmhdrjNJJHIftgSt0fuN5m48oLOnX7vvkz+X0WLWfVTtMr0w==
21-----END CERTIFICATE----- 24-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/server-key.pem b/plugins/tests/certs/server-key.pem
index eacaeaa..0de63f8 100644
--- a/plugins/tests/certs/server-key.pem
+++ b/plugins/tests/certs/server-key.pem
@@ -1,15 +1,28 @@
1-----BEGIN RSA PRIVATE KEY----- 1-----BEGIN PRIVATE KEY-----
2MIICWwIBAAKBgQCnFjAbTbX2PL2V5NEjevxGE1Tfyzr2jknoMqFXS6BsLsI2oJPl 2MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDb/d4EDhYbrHMt
35gs7wqh2UafJZwi2suwDvAECO00jdNooQnEq4BgPTk/h3IiCdZef5BGFALgNT0em 38zrFxbLDFOFvVGntcBbd7BB33892hZcR7wElaUt/JiLV2ssxywPLCEuQqZbhWn3V
4Civ0+9d81AJTM8trbLoMefsUrEhMLF5Jp3udoyYhv8LhOQi09PaRfB0KhwIDAQAB 4Hg8CSKWOOsH9lpQwMsnWuLd3BfhG9cbtyuxTdBYVYIE6t/lXYVNFDab8f8rIH/qt
5AoGAfpxclcP8N3vteXErXURrd7pcXT0GECDgNjhvc9PV20RPXM+vYs1AA+fMeeQE 5VkA2xTjsepMVI+JSbaPs/fDH/C0d5gL6qY0bvNlOMBg9jF8qKh3SXK1NKZv6Hnjq
6TaRqwO6x016aMRO4rz5ztYArecTBznkds1k59pkN/Ne/nsueU4tvGK8MNyS2o986 6XGff5U8RdkBBmUu8+eb/nwmdcatS/sHbKhx/kyEqQsk6sbEfaF/AohJ9qPaCk5Wb
7Voohqkaq4Lcy1bcHJb9su1ELjegEr1R76Mz452Hsy+uTbAECQQDcg/tZWKVeh5CQ 7g9RViIPMJKmrV8+/BtTEi907bvGmvH6asY4Uzp/ZQIQ5zfnDwVKZiJHbJBOcQkql
8dOEB3YWHwfn0NDgfPm/X2i2kAZ7n7URaUy/ffdlfsrr1mBtHCfedLoOxmmlNfEpM 8tJAPq3WNAgMBAAECggEBAIvJDUjQVpXxByL8eazviT5SR0jBf6mC3tTWykQRb7ck
9hXAAurSHAkEAwfk7fEb0iN0Sj9gTozO7c6Ky10KwePZyjVzqSQIiJq3NX8BEaIeb 9/bBEiRrnhDRf3CS9KP4TvO5G8BUU3a2GHYzM08akuKXeiiODidfyfbQ1nUZBAdi9
1051TXxE5VxaLjjMLRkA0hWTYXClgERFZ6AQJAN7ChPqwzf08PRFwwIw911JY5cOHr 10FVFF7tK8YcflkVfpTMOMMSggm6m33fc58sQvmQ/0U85XuJvnOEkeJ9pQJa49e8GR
11NoDHMCUql5vNLNdwBruxgGjBB/kUXEfgw60RusFvgt/zLh1wiii844JDawJAGQBF 11lpCQImF7ygltHPEz4o8qOtNMuPxiHOxpc517+ozQULZk153NTfGok1XctDFFZ3YX
12sYP3urg7zzx7c3qUe5gJ0wLuefjR1PSX4ecbfb7DDMdcSdjIuG1QDiZGmd2f1KG7 128okLSfcqZ28mdHYSvI9xf60Cm7cT9tunXHwZ0f1esTFiVYpAp+oTJqtdYxr/fYlL
13nwSCOtxk5dloW2KGAQJAQh/iBn0QhfKLFAP5eZBVk8E8XlZuw+S2DLy5SnBlIiYJ 13oO8G8iIQ7LjdJfgo84PscpKdSRCq3BfnmER1Eyg6hrUCgYEA/0hL5Y/haz/2jYGy
14GB5I2OClgtudXMv1labFrcST8O9eFrtsrhU1iUGUOw== 14aa8yZSuD1ZcWtj7pLKrBQnHPHIHsjSBggWhopvonCFvCjgSS1pOFOUAwMGc0T+Dw
15-----END RSA PRIVATE KEY----- 15rWo3w8cEUyECl3Bw8gbCWtRXaigzU9TPgCWyx1j5dTopQhLObzS/m7fJFElnYNru
16jqhsUfWS+NKk8a5+A7i9lv4iBLMCgYEA3Jws3Lfj/Xs7LljrvryTMpPthvUGBcyt
17U9Qmf1Hmur90RP5V1rx4FqPQzIeaGQyZDNIUnkhBSqQZNCts3Rzay7N4uQzk8OEg
18S8Llnw76wLwi0SJ4okDtT5tpTR6fcS0M9lGN+zvvfUB4+ul8oub0pMcyme/pywEz
19ap+x3xAQPL8CgYEAiYOBVtTNof9fqdRurh1w8SyipKDx3BRBeQ02c7tozLt0GIWT
20VsJOdXwVIJyFTglKrAnlXvSjwL8nX8wU+eVYyr5fJwSGJ9urC8T2VwVBXW7wTz04
211Zf5GQdlwW8mIHCPATqR6Kj0yVfNN1BX50L0rqWxmRWnQoUzXn/aqQaWfp8CgYAW
229693/zEeR8EejyVkAy/z+RCml0XcPrXg31pusPErihkpwazgIVkDSmTHlmqFpxkc
23C5cX73/UrIbvNoIr9wAUawfrhBsltNpu6MiNKbsTa8LYMRWMFuReAFkTLVf+KWmL
24D2yPtmq1iIvP25UdRJw9t3teKWsWtnZK6HtVNM/r8wKBgQDKlqUpy8r4KK+S2w80
25H7rAQJo1DgXsYrgSa2gfppSKro4lm3ltyAfVIrKQKP7uCo9xTGKVQAUPttMs2+17
26nwbwvt7/nG7G1Dk/C/t6b7SJ80VY5b9ZZKIJ0wOjajLufSjPNCe0ZTRn32XusZUn
27nYGB5/QXYr5WGV9YhAkRsFJYgA==
28-----END PRIVATE KEY-----
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t
new file mode 100755
index 0000000..72f2b7c
--- /dev/null
+++ b/plugins/tests/check_curl.t
@@ -0,0 +1,526 @@
1#! /usr/bin/perl -w -I ..
2#
3# Test check_http by having an actual HTTP server running
4#
5# To create the https server certificate:
6# openssl req -new -x509 -keyout server-key.pem -out server-cert.pem -days 3650 -nodes
7# to create a new expired certificate:
8# faketime '2008-01-01 12:00:00' openssl req -new -x509 -keyout expired-key.pem -out expired-cert.pem -days 1 -nodes
9# Country Name (2 letter code) [AU]:DE
10# State or Province Name (full name) [Some-State]:Bavaria
11# Locality Name (eg, city) []:Munich
12# Organization Name (eg, company) [Internet Widgits Pty Ltd]:Monitoring Plugins
13# Organizational Unit Name (eg, section) []:
14# Common Name (e.g. server FQDN or YOUR name) []:Monitoring Plugins
15# Email Address []:devel@monitoring-plugins.org
16
17use strict;
18use Test::More;
19use NPTest;
20use FindBin qw($Bin);
21
22$ENV{'LC_TIME'} = "C";
23
24my $common_tests = 73;
25my $ssl_only_tests = 8;
26# Check that all dependent modules are available
27eval "use HTTP::Daemon 6.01;";
28plan skip_all => 'HTTP::Daemon >= 6.01 required' if $@;
29eval {
30 require HTTP::Status;
31 require HTTP::Response;
32};
33
34my $plugin = 'check_http';
35$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
36
37# look for libcurl version to see if some advanced checks are possible (>= 7.49.0)
38my $advanced_checks = 12;
39my $use_advanced_checks = 0;
40my $required_version = '7.49.0';
41my $virtual_host = 'www.somefunnyhost.com';
42my $virtual_port = 42;
43my $curl_version = '';
44open (my $fh, '-|', "./$plugin --version") or die;
45while (<$fh>) {
46 if (m{libcurl/([\d.]+)\s}) {
47 $curl_version = $1;
48 last;
49 }
50}
51close ($fh);
52if ($curl_version) {
53 my ($major, $minor, $release) = split (/\./, $curl_version);
54 my ($req_major, $req_minor, $req_release) = split (/\./, $required_version);
55 my $check = ($major <=> $req_major or $minor <=> $req_minor or $release <=> $req_release);
56 if ($check >= 0) {
57 $use_advanced_checks = 1;
58 print "Found libcurl $major.$minor.$release. Using advanced checks\n";
59 }
60}
61
62if ($@) {
63 plan skip_all => "Missing required module for test: $@";
64} else {
65 if (-x "./$plugin") {
66 plan tests => $common_tests * 2 + $ssl_only_tests + $advanced_checks;
67 } else {
68 plan skip_all => "No $plugin compiled";
69 }
70}
71
72my $servers = { http => 0 }; # HTTP::Daemon should always be available
73eval { require HTTP::Daemon::SSL };
74if ($@) {
75 diag "Cannot load HTTP::Daemon::SSL: $@";
76} else {
77 $servers->{https} = 0;
78}
79
80# set a fixed version, so the header size doesn't vary
81$HTTP::Daemon::VERSION = "1.00";
82
83my $port_http = 50000 + int(rand(1000));
84my $port_https = $port_http + 1;
85my $port_https_expired = $port_http + 2;
86
87# This array keeps sockets around for implementing timeouts
88my @persist;
89
90# Start up all servers
91my @pids;
92my $pid = fork();
93if ($pid) {
94 # Parent
95 push @pids, $pid;
96 if (exists $servers->{https}) {
97 # Fork a normal HTTPS server
98 $pid = fork();
99 if ($pid) {
100 # Parent
101 push @pids, $pid;
102 # Fork an expired cert server
103 $pid = fork();
104 if ($pid) {
105 push @pids, $pid;
106 } else {
107 my $d = HTTP::Daemon::SSL->new(
108 LocalPort => $port_https_expired,
109 LocalAddr => "127.0.0.1",
110 SSL_cert_file => "$Bin/certs/expired-cert.pem",
111 SSL_key_file => "$Bin/certs/expired-key.pem",
112 ) || die;
113 print "Please contact https expired at: <URL:", $d->url, ">\n";
114 run_server( $d );
115 exit;
116 }
117 } else {
118 my $d = HTTP::Daemon::SSL->new(
119 LocalPort => $port_https,
120 LocalAddr => "127.0.0.1",
121 SSL_cert_file => "$Bin/certs/server-cert.pem",
122 SSL_key_file => "$Bin/certs/server-key.pem",
123 ) || die;
124 print "Please contact https at: <URL:", $d->url, ">\n";
125 run_server( $d );
126 exit;
127 }
128 }
129} else {
130 # Child
131 #print "child\n";
132 my $d = HTTP::Daemon->new(
133 LocalPort => $port_http,
134 LocalAddr => "127.0.0.1",
135 ) || die;
136 print "Please contact http at: <URL:", $d->url, ">\n";
137 run_server( $d );
138 exit;
139}
140
141# give our webservers some time to startup
142sleep(3);
143
144# Run the same server on http and https
145sub run_server {
146 my $d = shift;
147 MAINLOOP: while (my $c = $d->accept ) {
148 while (my $r = $c->get_request) {
149 if ($r->method eq "GET" and $r->url->path =~ m^/statuscode/(\d+)^) {
150 $c->send_basic_header($1);
151 $c->send_crlf;
152 } elsif ($r->method eq "GET" and $r->url->path =~ m^/file/(.*)^) {
153 $c->send_basic_header;
154 $c->send_crlf;
155 $c->send_file_response("$Bin/var/$1");
156 } elsif ($r->method eq "GET" and $r->url->path eq "/slow") {
157 $c->send_basic_header;
158 $c->send_crlf;
159 sleep 1;
160 $c->send_response("slow");
161 } elsif ($r->url->path eq "/method") {
162 if ($r->method eq "DELETE") {
163 $c->send_error(HTTP::Status->RC_METHOD_NOT_ALLOWED);
164 } elsif ($r->method eq "foo") {
165 $c->send_error(HTTP::Status->RC_NOT_IMPLEMENTED);
166 } else {
167 $c->send_status_line(200, $r->method);
168 }
169 } elsif ($r->url->path eq "/postdata") {
170 $c->send_basic_header;
171 $c->send_crlf;
172 $c->send_response($r->method.":".$r->content);
173 } elsif ($r->url->path eq "/redirect") {
174 $c->send_redirect( "/redirect2" );
175 } elsif ($r->url->path eq "/redir_external") {
176 $c->send_redirect(($d->isa('HTTP::Daemon::SSL') ? "https" : "http") . "://169.254.169.254/redirect2" );
177 } elsif ($r->url->path eq "/redirect2") {
178 $c->send_basic_header;
179 $c->send_crlf;
180 $c->send_response(HTTP::Response->new( 200, 'OK', undef, 'redirected' ));
181 } elsif ($r->url->path eq "/redir_timeout") {
182 $c->send_redirect( "/timeout" );
183 } elsif ($r->url->path eq "/timeout") {
184 # Keep $c from being destroyed, but prevent severe leaks
185 unshift @persist, $c;
186 delete($persist[1000]);
187 next MAINLOOP;
188 } elsif ($r->url->path eq "/header_check") {
189 $c->send_basic_header;
190 $c->send_header('foo');
191 $c->send_crlf;
192 } elsif ($r->url->path eq "/header_broken_check") {
193 $c->send_basic_header;
194 $c->send_header('foo');
195 print $c "Test1:: broken\n";
196 print $c " Test2: leading whitespace\n";
197 $c->send_crlf;
198 } elsif ($r->url->path eq "/virtual_port") {
199 # return sent Host header
200 $c->send_basic_header;
201 $c->send_crlf;
202 $c->send_response(HTTP::Response->new( 200, 'OK', undef, $r->header ('Host')));
203 } elsif ($r->url->path eq "/chunked") {
204 my $chunks = ["chunked", "encoding", "test\n"];
205 $c->send_response(HTTP::Response->new( 200, 'OK', undef, sub {
206 my $chunk = shift @{$chunks};
207 return unless $chunk;
208 sleep(1);
209 return($chunk);
210 }));
211 } else {
212 $c->send_error(HTTP::Status->RC_FORBIDDEN);
213 }
214 $c->close;
215 }
216 }
217}
218
219END {
220 foreach my $pid (@pids) {
221 if ($pid) { print "Killing $pid\n"; kill "INT", $pid }
222 }
223};
224
225if ($ARGV[0] && $ARGV[0] eq "-d") {
226 while (1) {
227 sleep 100;
228 }
229}
230
231my $result;
232my $command = "./$plugin -H 127.0.0.1";
233
234run_common_tests( { command => "$command -p $port_http" } );
235SKIP: {
236 skip "HTTP::Daemon::SSL not installed", $common_tests + $ssl_only_tests if ! exists $servers->{https};
237 run_common_tests( { command => "$command -p $port_https", ssl => 1 } );
238
239 my $expiry = "Thu Nov 28 21:02:11 2030 +0000";
240
241 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
242 is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
243 is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" );
244
245 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
246 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
247 like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
248
249 # Expired cert tests
250 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
251 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
252 like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
253
254 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
255 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
256 is( $result->output,
257 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.',
258 "output ok" );
259
260}
261
262my $cmd;
263
264# advanced checks with virtual hostname and virtual port
265SKIP: {
266 skip "libcurl version is smaller than $required_version", 6 unless $use_advanced_checks;
267
268 # http without virtual port
269 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$";
270 $result = NPTest->testCmd( $cmd );
271 is( $result->return_code, 0, $cmd);
272 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
273
274 # http with virtual port (!= 80)
275 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$";
276 $result = NPTest->testCmd( $cmd );
277 is( $result->return_code, 0, $cmd);
278 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
279
280 # http with virtual port (80)
281 $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$";
282 $result = NPTest->testCmd( $cmd );
283 is( $result->return_code, 0, $cmd);
284 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
285}
286
287# and the same for SSL
288SKIP: {
289 skip "libcurl version is smaller than $required_version and/or HTTP::Daemon::SSL not installed", 6 if ! exists $servers->{https} or not $use_advanced_checks;
290 # https without virtual port
291 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$";
292 $result = NPTest->testCmd( $cmd );
293 is( $result->return_code, 0, $cmd);
294 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
295
296 # https with virtual port (!= 443)
297 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$";
298 $result = NPTest->testCmd( $cmd );
299 is( $result->return_code, 0, $cmd);
300 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
301
302 # https with virtual port (443)
303 $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$";
304 $result = NPTest->testCmd( $cmd );
305 is( $result->return_code, 0, $cmd);
306 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
307}
308
309
310sub run_common_tests {
311 my ($opts) = @_;
312 my $command = $opts->{command};
313 if ($opts->{ssl}) {
314 $command .= " --ssl";
315 }
316
317 $result = NPTest->testCmd( "$command -u /file/root" );
318 is( $result->return_code, 0, "/file/root");
319 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
320
321 $result = NPTest->testCmd( "$command -u /file/root -s Root" );
322 is( $result->return_code, 0, "/file/root search for string");
323 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
324
325 $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" );
326 is( $result->return_code, 2, "Missing string check");
327 like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
328
329 $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" );
330 is( $result->return_code, 2, "Missing string check");
331 like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
332
333 $result = NPTest->testCmd( "$command -u /header_check -d foo" );
334 is( $result->return_code, 0, "header_check search for string");
335 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" );
336
337 $result = NPTest->testCmd( "$command -u /header_check -d bar" );
338 is( $result->return_code, 2, "Missing header string check");
339 like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
340
341 $result = NPTest->testCmd( "$command -u /header_broken_check" );
342 is( $result->return_code, 0, "header_check search for string");
343 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second/', "Output correct" );
344
345 my $cmd;
346 $cmd = "$command -u /slow";
347 $result = NPTest->testCmd( $cmd );
348 is( $result->return_code, 0, "$cmd");
349 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
350 $result->output =~ /in ([\d\.]+) second/;
351 cmp_ok( $1, ">", 1, "Time is > 1 second" );
352
353 $cmd = "$command -u /statuscode/200";
354 $result = NPTest->testCmd( $cmd );
355 is( $result->return_code, 0, $cmd);
356 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
357
358 $cmd = "$command -u /statuscode/200 -e 200";
359 $result = NPTest->testCmd( $cmd );
360 is( $result->return_code, 0, $cmd);
361 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
362
363 $cmd = "$command -u /statuscode/201";
364 $result = NPTest->testCmd( $cmd );
365 is( $result->return_code, 0, $cmd);
366 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
367
368 $cmd = "$command -u /statuscode/201 -e 201";
369 $result = NPTest->testCmd( $cmd );
370 is( $result->return_code, 0, $cmd);
371 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
372
373 $cmd = "$command -u /statuscode/201 -e 200";
374 $result = NPTest->testCmd( $cmd );
375 is( $result->return_code, 2, $cmd);
376 like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output );
377
378 $cmd = "$command -u /statuscode/200 -e 200,201,202";
379 $result = NPTest->testCmd( $cmd );
380 is( $result->return_code, 0, $cmd);
381 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
382
383 $cmd = "$command -u /statuscode/201 -e 200,201,202";
384 $result = NPTest->testCmd( $cmd );
385 is( $result->return_code, 0, $cmd);
386 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
387
388 $cmd = "$command -u /statuscode/203 -e 200,201,202";
389 $result = NPTest->testCmd( $cmd );
390 is( $result->return_code, 2, $cmd);
391 like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output );
392
393 $cmd = "$command -j HEAD -u /method";
394 $result = NPTest->testCmd( $cmd );
395 is( $result->return_code, 0, $cmd);
396 like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
397
398 $cmd = "$command -j POST -u /method";
399 $result = NPTest->testCmd( $cmd );
400 is( $result->return_code, 0, $cmd);
401 like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
402
403 $cmd = "$command -j GET -u /method";
404 $result = NPTest->testCmd( $cmd );
405 is( $result->return_code, 0, $cmd);
406 like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
407
408 $cmd = "$command -u /method";
409 $result = NPTest->testCmd( $cmd );
410 is( $result->return_code, 0, $cmd);
411 like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
412
413 $cmd = "$command -P foo -u /method";
414 $result = NPTest->testCmd( $cmd );
415 is( $result->return_code, 0, $cmd);
416 like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
417
418 $cmd = "$command -j DELETE -u /method";
419 $result = NPTest->testCmd( $cmd );
420 is( $result->return_code, 1, $cmd);
421 like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output );
422
423 $cmd = "$command -j foo -u /method";
424 $result = NPTest->testCmd( $cmd );
425 is( $result->return_code, 2, $cmd);
426 like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output );
427
428 $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude";
429 $result = NPTest->testCmd( $cmd );
430 is( $result->return_code, 0, $cmd);
431 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
432
433 $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude";
434 $result = NPTest->testCmd( $cmd );
435 is( $result->return_code, 0, $cmd);
436 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
437
438 # To confirm that the free doesn't segfault
439 $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude";
440 $result = NPTest->testCmd( $cmd );
441 is( $result->return_code, 0, $cmd);
442 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
443
444 $cmd = "$command -u /redirect";
445 $result = NPTest->testCmd( $cmd );
446 is( $result->return_code, 0, $cmd);
447 like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
448
449 $cmd = "$command -f follow -u /redirect";
450 $result = NPTest->testCmd( $cmd );
451 is( $result->return_code, 0, $cmd);
452 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
453
454 $cmd = "$command -u /redirect -k 'follow: me'";
455 $result = NPTest->testCmd( $cmd );
456 is( $result->return_code, 0, $cmd);
457 like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
458
459 $cmd = "$command -f follow -u /redirect -k 'follow: me'";
460 $result = NPTest->testCmd( $cmd );
461 is( $result->return_code, 0, $cmd);
462 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
463
464 $cmd = "$command -f sticky -u /redirect -k 'follow: me'";
465 $result = NPTest->testCmd( $cmd );
466 is( $result->return_code, 0, $cmd);
467 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
468
469 $cmd = "$command -f stickyport -u /redirect -k 'follow: me'";
470 $result = NPTest->testCmd( $cmd );
471 is( $result->return_code, 0, $cmd);
472 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
473
474 # These tests may block
475 print "ALRM\n";
476
477 # stickyport - on full urlS port is set back to 80 otherwise
478 $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected";
479 eval {
480 local $SIG{ALRM} = sub { die "alarm\n" };
481 alarm(2);
482 $result = NPTest->testCmd( $cmd );
483 };
484 alarm(0);
485 isnt( $@, "alarm\n", $cmd );
486 is( $result->return_code, 0, $cmd );
487
488 # Let's hope there won't be any web server on :80 returning "redirected"!
489 $cmd = "$command -f sticky -u /redir_external -t 5 -s redirected";
490 eval {
491 local $SIG{ALRM} = sub { die "alarm\n" };
492 alarm(2);
493 $result = NPTest->testCmd( $cmd );
494 };
495 alarm(0);
496 isnt( $@, "alarm\n", $cmd );
497 isnt( $result->return_code, 0, $cmd );
498
499 # Test an external address - timeout
500 SKIP: {
501 skip "This doesn't seem to work all the time", 1 unless ($ENV{HTTP_EXTERNAL});
502 $cmd = "$command -f follow -u /redir_external -t 5";
503 eval {
504 $result = NPTest->testCmd( $cmd, 2 );
505 };
506 like( $@, "/timeout in command: $cmd/", $cmd );
507 }
508
509 $cmd = "$command -u /timeout -t 5";
510 eval {
511 $result = NPTest->testCmd( $cmd, 2 );
512 };
513 like( $@, "/timeout in command: $cmd/", $cmd );
514
515 $cmd = "$command -f follow -u /redir_timeout -t 2";
516 eval {
517 $result = NPTest->testCmd( $cmd, 5 );
518 };
519 is( $@, "", $cmd );
520
521 $cmd = "$command -u /chunked -s 'chunkedencodingtest' -d 'Transfer-Encoding: chunked'";
522 eval {
523 $result = NPTest->testCmd( $cmd, 5 );
524 };
525 is( $@, "", $cmd );
526}
diff --git a/plugins/tests/check_http.t b/plugins/tests/check_http.t
index d6d31de..6078b27 100755
--- a/plugins/tests/check_http.t
+++ b/plugins/tests/check_http.t
@@ -3,25 +3,20 @@
3# Test check_http by having an actual HTTP server running 3# Test check_http by having an actual HTTP server running
4# 4#
5# To create the https server certificate: 5# To create the https server certificate:
6# openssl req -new -x509 -keyout server-key.pem -out server-cert.pem -days 3650 -nodes 6# ./certs/generate-certs.sh
7# Country Name (2 letter code) [AU]:UK
8# State or Province Name (full name) [Some-State]:Derbyshire
9# Locality Name (eg, city) []:Belper
10# Organization Name (eg, company) [Internet Widgits Pty Ltd]:Monitoring Plugins
11# Organizational Unit Name (eg, section) []:
12# Common Name (eg, YOUR name) []:Ton Voon
13# Email Address []:tonvoon@mac.com
14 7
15use strict; 8use strict;
16use Test::More; 9use Test::More;
17use NPTest; 10use NPTest;
18use FindBin qw($Bin); 11use FindBin qw($Bin);
12use IO::Socket::INET;
19 13
20$ENV{'LC_TIME'} = "C"; 14$ENV{'LC_TIME'} = "C";
21 15
22my $common_tests = 70; 16my $common_tests = 71;
23my $virtual_port_tests = 8; 17my $virtual_port_tests = 8;
24my $ssl_only_tests = 8; 18my $ssl_only_tests = 12;
19my $chunked_encoding_special_tests = 1;
25# Check that all dependent modules are available 20# Check that all dependent modules are available
26eval "use HTTP::Daemon 6.01;"; 21eval "use HTTP::Daemon 6.01;";
27plan skip_all => 'HTTP::Daemon >= 6.01 required' if $@; 22plan skip_all => 'HTTP::Daemon >= 6.01 required' if $@;
@@ -30,13 +25,16 @@ eval {
30 require HTTP::Response; 25 require HTTP::Response;
31}; 26};
32 27
28my $plugin = 'check_http';
29$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
30
33if ($@) { 31if ($@) {
34 plan skip_all => "Missing required module for test: $@"; 32 plan skip_all => "Missing required module for test: $@";
35} else { 33} else {
36 if (-x "./check_http") { 34 if (-x "./$plugin") {
37 plan tests => $common_tests * 2 + $ssl_only_tests + $virtual_port_tests; 35 plan tests => $common_tests * 2 + $ssl_only_tests + $virtual_port_tests + $chunked_encoding_special_tests;
38 } else { 36 } else {
39 plan skip_all => "No check_http compiled"; 37 plan skip_all => "No $plugin compiled";
40 } 38 }
41} 39}
42 40
@@ -54,124 +52,217 @@ $HTTP::Daemon::VERSION = "1.00";
54my $port_http = 50000 + int(rand(1000)); 52my $port_http = 50000 + int(rand(1000));
55my $port_https = $port_http + 1; 53my $port_https = $port_http + 1;
56my $port_https_expired = $port_http + 2; 54my $port_https_expired = $port_http + 2;
55my $port_https_clientcert = $port_http + 3;
56my $port_hacked_http = $port_http + 4;
57 57
58# This array keeps sockets around for implementing timeouts 58# This array keeps sockets around for implementing timeouts
59my @persist; 59my @persist;
60 60
61# Start up all servers 61# Start up all servers
62my @pids; 62my @pids;
63my $pid = fork(); 63# Fork a HTTP server
64if ($pid) { 64my $pid = fork;
65 # Parent 65defined $pid or die "Failed to fork";
66 push @pids, $pid; 66if (!$pid) {
67 if (exists $servers->{https}) { 67 undef @pids;
68 # Fork a normal HTTPS server
69 $pid = fork();
70 if ($pid) {
71 # Parent
72 push @pids, $pid;
73 # Fork an expired cert server
74 $pid = fork();
75 if ($pid) {
76 push @pids, $pid;
77 } else {
78 my $d = HTTP::Daemon::SSL->new(
79 LocalPort => $port_https_expired,
80 LocalAddr => "127.0.0.1",
81 SSL_cert_file => "$Bin/certs/expired-cert.pem",
82 SSL_key_file => "$Bin/certs/expired-key.pem",
83 ) || die;
84 print "Please contact https expired at: <URL:", $d->url, ">\n";
85 run_server( $d );
86 exit;
87 }
88 } else {
89 my $d = HTTP::Daemon::SSL->new(
90 LocalPort => $port_https,
91 LocalAddr => "127.0.0.1",
92 SSL_cert_file => "$Bin/certs/server-cert.pem",
93 SSL_key_file => "$Bin/certs/server-key.pem",
94 ) || die;
95 print "Please contact https at: <URL:", $d->url, ">\n";
96 run_server( $d );
97 exit;
98 }
99 }
100 # give our webservers some time to startup
101 sleep(1);
102} else {
103 # Child
104 #print "child\n";
105 my $d = HTTP::Daemon->new( 68 my $d = HTTP::Daemon->new(
106 LocalPort => $port_http, 69 LocalPort => $port_http,
107 LocalAddr => "127.0.0.1", 70 LocalAddr => "127.0.0.1",
108 ) || die; 71 ) || die;
109 print "Please contact http at: <URL:", $d->url, ">\n"; 72 print "Please contact http at: <URL:", $d->url, ">\n";
110 run_server( $d ); 73 run_server( $d );
111 exit; 74 die "webserver stopped";
75}
76push @pids, $pid;
77
78# Fork the hacked HTTP server
79undef $pid;
80$pid = fork;
81defined $pid or die "Failed to fork";
82if (!$pid) {
83 # this is the fork
84 undef @pids;
85 my $socket = new IO::Socket::INET (
86 LocalHost => '0.0.0.0',
87 LocalPort => $port_hacked_http,
88 Proto => 'tcp',
89 Listen => 5,
90 Reuse => 1
91 );
92 die "cannot create socket $!n" unless $socket;
93 my $local_sock = $socket->sockport();
94 print "server waiting for client connection on port $local_sock\n";
95 run_hacked_http_server ( $socket );
96 die "hacked http server stopped";
112} 97}
98push @pids, $pid;
99
100if (exists $servers->{https}) {
101 # Fork a normal HTTPS server
102 $pid = fork;
103 defined $pid or die "Failed to fork";
104 if (!$pid) {
105 undef @pids;
106 # closing the connection after -C cert checks make the daemon exit with a sigpipe otherwise
107 local $SIG{'PIPE'} = 'IGNORE';
108 my $d = HTTP::Daemon::SSL->new(
109 LocalPort => $port_https,
110 LocalAddr => "127.0.0.1",
111 SSL_cert_file => "$Bin/certs/server-cert.pem",
112 SSL_key_file => "$Bin/certs/server-key.pem",
113 ) || die;
114 print "Please contact https at: <URL:", $d->url, ">\n";
115 run_server( $d );
116 die "webserver stopped";
117 }
118 push @pids, $pid;
119
120 # Fork an expired cert server
121 $pid = fork;
122 defined $pid or die "Failed to fork";
123 if (!$pid) {
124 undef @pids;
125 # closing the connection after -C cert checks make the daemon exit with a sigpipe otherwise
126 local $SIG{'PIPE'} = 'IGNORE';
127 my $d = HTTP::Daemon::SSL->new(
128 LocalPort => $port_https_expired,
129 LocalAddr => "127.0.0.1",
130 SSL_cert_file => "$Bin/certs/expired-cert.pem",
131 SSL_key_file => "$Bin/certs/expired-key.pem",
132 ) || die;
133 print "Please contact https expired at: <URL:", $d->url, ">\n";
134 run_server( $d );
135 die "webserver stopped";
136 }
137 push @pids, $pid;
138
139 # Fork an client cert expecting server
140 $pid = fork;
141 defined $pid or die "Failed to fork";
142 if (!$pid) {
143 undef @pids;
144 # closing the connection after -C cert checks make the daemon exit with a sigpipe otherwise
145 local $SIG{'PIPE'} = 'IGNORE';
146 my $d = HTTP::Daemon::SSL->new(
147 LocalPort => $port_https_clientcert,
148 LocalAddr => "127.0.0.1",
149 SSL_cert_file => "$Bin/certs/server-cert.pem",
150 SSL_key_file => "$Bin/certs/server-key.pem",
151 SSL_verify_mode => IO::Socket::SSL->SSL_VERIFY_PEER | IO::Socket::SSL->SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
152 SSL_ca_file => "$Bin/certs/clientca-cert.pem",
153 ) || die;
154 print "Please contact https client cert at: <URL:", $d->url, ">\n";
155 run_server( $d );
156 die "webserver stopped";
157 }
158 push @pids, $pid;
159}
160
161# give our webservers some time to startup
162sleep(3);
113 163
114# Run the same server on http and https 164# Run the same server on http and https
115sub run_server { 165sub run_server {
116 my $d = shift; 166 my $d = shift;
117 MAINLOOP: while (my $c = $d->accept ) { 167 while (1) {
118 while (my $r = $c->get_request) { 168 MAINLOOP: while (my $c = $d->accept) {
119 if ($r->method eq "GET" and $r->url->path =~ m^/statuscode/(\d+)^) { 169 while (my $r = $c->get_request) {
120 $c->send_basic_header($1); 170 if ($r->method eq "GET" and $r->url->path =~ m^/statuscode/(\d+)^) {
121 $c->send_crlf; 171 $c->send_basic_header($1);
122 } elsif ($r->method eq "GET" and $r->url->path =~ m^/file/(.*)^) { 172 $c->send_crlf;
123 $c->send_basic_header; 173 } elsif ($r->method eq "GET" and $r->url->path =~ m^/file/(.*)^) {
124 $c->send_crlf; 174 $c->send_basic_header;
125 $c->send_file_response("$Bin/var/$1"); 175 $c->send_crlf;
126 } elsif ($r->method eq "GET" and $r->url->path eq "/slow") { 176 $c->send_file_response("$Bin/var/$1");
127 $c->send_basic_header; 177 } elsif ($r->method eq "GET" and $r->url->path eq "/slow") {
128 $c->send_crlf; 178 $c->send_basic_header;
129 sleep 1; 179 $c->send_crlf;
130 $c->send_response("slow"); 180 sleep 1;
131 } elsif ($r->url->path eq "/method") { 181 $c->send_response("slow");
132 if ($r->method eq "DELETE") { 182 } elsif ($r->url->path eq "/method") {
133 $c->send_error(HTTP::Status->RC_METHOD_NOT_ALLOWED); 183 if ($r->method eq "DELETE") {
134 } elsif ($r->method eq "foo") { 184 $c->send_error(HTTP::Status->RC_METHOD_NOT_ALLOWED);
135 $c->send_error(HTTP::Status->RC_NOT_IMPLEMENTED); 185 } elsif ($r->method eq "foo") {
186 $c->send_error(HTTP::Status->RC_NOT_IMPLEMENTED);
187 } else {
188 $c->send_status_line(200, $r->method);
189 }
190 } elsif ($r->url->path eq "/postdata") {
191 $c->send_basic_header;
192 $c->send_crlf;
193 $c->send_response($r->method.":".$r->content);
194 } elsif ($r->url->path eq "/redirect") {
195 $c->send_redirect( "/redirect2" );
196 } elsif ($r->url->path eq "/redir_external") {
197 $c->send_redirect(($d->isa('HTTP::Daemon::SSL') ? "https" : "http") . "://169.254.169.254/redirect2" );
198 } elsif ($r->url->path eq "/redirect2") {
199 $c->send_basic_header;
200 $c->send_crlf;
201 $c->send_response(HTTP::Response->new( 200, 'OK', undef, 'redirected' ));
202 } elsif ($r->url->path eq "/redir_timeout") {
203 $c->send_redirect( "/timeout" );
204 } elsif ($r->url->path eq "/timeout") {
205 # Keep $c from being destroyed, but prevent severe leaks
206 unshift @persist, $c;
207 delete($persist[1000]);
208 next MAINLOOP;
209 } elsif ($r->url->path eq "/header_check") {
210 $c->send_basic_header;
211 $c->send_header('foo');
212 $c->send_crlf;
213 } elsif ($r->url->path eq "/virtual_port") {
214 # return sent Host header
215 $c->send_basic_header;
216 $c->send_crlf;
217 $c->send_response(HTTP::Response->new( 200, 'OK', undef, $r->header ('Host')));
218 } elsif ($r->url->path eq "/chunked") {
219 my $chunks = ["chunked", "encoding", "test\n"];
220 $c->send_response(HTTP::Response->new( 200, 'OK', undef, sub {
221 my $chunk = shift @{$chunks};
222 return unless $chunk;
223 sleep(1);
224 return($chunk);
225 }));
136 } else { 226 } else {
137 $c->send_status_line(200, $r->method); 227 $c->send_error(HTTP::Status->RC_FORBIDDEN);
138 } 228 }
139 } elsif ($r->url->path eq "/postdata") { 229 $c->close;
140 $c->send_basic_header;
141 $c->send_crlf;
142 $c->send_response($r->method.":".$r->content);
143 } elsif ($r->url->path eq "/redirect") {
144 $c->send_redirect( "/redirect2" );
145 } elsif ($r->url->path eq "/redir_external") {
146 $c->send_redirect(($d->isa('HTTP::Daemon::SSL') ? "https" : "http") . "://169.254.169.254/redirect2" );
147 } elsif ($r->url->path eq "/redirect2") {
148 $c->send_basic_header;
149 $c->send_crlf;
150 $c->send_response(HTTP::Response->new( 200, 'OK', undef, 'redirected' ));
151 } elsif ($r->url->path eq "/redir_timeout") {
152 $c->send_redirect( "/timeout" );
153 } elsif ($r->url->path eq "/timeout") {
154 # Keep $c from being destroyed, but prevent severe leaks
155 unshift @persist, $c;
156 delete($persist[1000]);
157 next MAINLOOP;
158 } elsif ($r->url->path eq "/header_check") {
159 $c->send_basic_header;
160 $c->send_header('foo');
161 $c->send_crlf;
162 } elsif ($r->url->path eq "/virtual_port") {
163 # return sent Host header
164 $c->send_basic_header;
165 $c->send_crlf;
166 $c->send_response(HTTP::Response->new( 200, 'OK', undef, $r->header ('Host')));
167 } else {
168 $c->send_error(HTTP::Status->RC_FORBIDDEN);
169 } 230 }
170 $c->close;
171 } 231 }
172 } 232 }
173} 233}
174 234
235sub run_hacked_http_server {
236 my $socket = shift;
237
238 # auto-flush on socket
239 $| = 1;
240
241
242 while(1)
243 {
244 # waiting for a new client connection
245 my $client_socket = $socket->accept();
246
247 # get information about a newly connected client
248 my $client_address = $client_socket->peerhost();
249 my $client_portn = $client_socket->peerport();
250 print "connection from $client_address:$client_portn";
251
252 # read up to 1024 characters from the connected client
253 my $data = "";
254 $client_socket->recv($data, 1024);
255 print "received data: $data";
256
257 # write response data to the connected client
258 $data = "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n";
259 $client_socket->send($data);
260
261 # notify client that response has been sent
262 shutdown($client_socket, 1);
263 }
264}
265
175END { 266END {
176 foreach my $pid (@pids) { 267 foreach my $pid (@pids) {
177 if ($pid) { print "Killing $pid\n"; kill "INT", $pid } 268 if ($pid) { print "Killing $pid\n"; kill "INT", $pid }
@@ -185,32 +276,52 @@ if ($ARGV[0] && $ARGV[0] eq "-d") {
185} 276}
186 277
187my $result; 278my $result;
188my $command = "./check_http -H 127.0.0.1"; 279my $command = "./$plugin -H 127.0.0.1";
189 280
281run_chunked_encoding_special_test( {command => "$command -p $port_hacked_http"});
190run_common_tests( { command => "$command -p $port_http" } ); 282run_common_tests( { command => "$command -p $port_http" } );
191SKIP: { 283SKIP: {
192 skip "HTTP::Daemon::SSL not installed", $common_tests + $ssl_only_tests if ! exists $servers->{https}; 284 skip "HTTP::Daemon::SSL not installed", $common_tests + $ssl_only_tests if ! exists $servers->{https};
193 run_common_tests( { command => "$command -p $port_https", ssl => 1 } ); 285 run_common_tests( { command => "$command -p $port_https", ssl => 1 } );
194 286
287 my $expiry = "Thu Nov 28 21:02:11 2030 +0000";
288
195 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" ); 289 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
196 is( $result->return_code, 0, "$command -p $port_https -S -C 14" ); 290 is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
197 is( $result->output, 'OK - Certificate \'Ton Voon\' will expire on Sun Mar 3 21:41:28 2019 +0000.', "output ok" ); 291 is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" );
198 292
199 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" ); 293 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
200 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" ); 294 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
201 like( $result->output, '/WARNING - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(Sun Mar 3 21:41:28 2019 \+0000\)./', "output ok" ); 295 like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
202 296
203 # Expired cert tests 297 # Expired cert tests
204 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" ); 298 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
205 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" ); 299 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
206 like( $result->output, '/CRITICAL - Certificate \'Ton Voon\' expires in \d+ day\(s\) \(Sun Mar 3 21:41:28 2019 \+0000\)./', "output ok" ); 300 like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
207 301
208 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" ); 302 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
209 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" ); 303 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
210 is( $result->output, 304 is( $result->output,
211 'CRITICAL - Certificate \'Ton Voon\' expired on Thu Mar 5 00:13:16 2009 +0000.', 305 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.',
212 "output ok" ); 306 "output ok" );
213 307
308 # client cert tests
309 my $cmd;
310 $cmd = "$command -p $port_https_clientcert"
311 . " -J \"$Bin/certs/client-cert.pem\""
312 . " -K \"$Bin/certs/client-key.pem\""
313 . " -u /statuscode/200";
314 $result = NPTest->testCmd($cmd);
315 is( $result->return_code, 0, $cmd);
316 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
317
318 $cmd = "$command -p $port_https_clientcert"
319 . " -J \"$Bin/certs/clientchain-cert.pem\""
320 . " -K \"$Bin/certs/clientchain-key.pem\""
321 . " -u /statuscode/200";
322 $result = NPTest->testCmd($cmd);
323 is( $result->return_code, 0, $cmd);
324 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
214} 325}
215 326
216my $cmd; 327my $cmd;
@@ -409,22 +520,24 @@ sub run_common_tests {
409 520
410 # stickyport - on full urlS port is set back to 80 otherwise 521 # stickyport - on full urlS port is set back to 80 otherwise
411 $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected"; 522 $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected";
523 alarm(2);
412 eval { 524 eval {
413 local $SIG{ALRM} = sub { die "alarm\n" }; 525 local $SIG{ALRM} = sub { die "alarm\n" };
414 alarm(2);
415 $result = NPTest->testCmd( $cmd ); 526 $result = NPTest->testCmd( $cmd );
416 alarm(0); }; 527 };
417 isnt( $@, "alarm\n", $cmd ); 528 isnt( $@, "alarm\n", $cmd );
529 alarm(0);
418 is( $result->return_code, 0, $cmd ); 530 is( $result->return_code, 0, $cmd );
419 531
420 # Let's hope there won't be any web server on :80 returning "redirected"! 532 # Let's hope there won't be any web server on :80 returning "redirected"!
421 $cmd = "$command -f sticky -u /redir_external -t 5 -s redirected"; 533 $cmd = "$command -f sticky -u /redir_external -t 5 -s redirected";
534 alarm(2);
422 eval { 535 eval {
423 local $SIG{ALRM} = sub { die "alarm\n" }; 536 local $SIG{ALRM} = sub { die "alarm\n" };
424 alarm(2);
425 $result = NPTest->testCmd( $cmd ); 537 $result = NPTest->testCmd( $cmd );
426 alarm(0); }; 538 };
427 isnt( $@, "alarm\n", $cmd ); 539 isnt( $@, "alarm\n", $cmd );
540 alarm(0);
428 isnt( $result->return_code, 0, $cmd ); 541 isnt( $result->return_code, 0, $cmd );
429 542
430 # Test an external address - timeout 543 # Test an external address - timeout
@@ -449,4 +562,20 @@ sub run_common_tests {
449 }; 562 };
450 is( $@, "", $cmd ); 563 is( $@, "", $cmd );
451 564
565 $cmd = "$command -u /chunked -s 'chunkedencodingtest' -d 'Transfer-Encoding: chunked'";
566 eval {
567 $result = NPTest->testCmd( $cmd, 5 );
568 };
569 is( $@, "", $cmd );
570}
571
572sub run_chunked_encoding_special_test {
573 my ($opts) = @_;
574 my $command = $opts->{command};
575
576 $cmd = "$command -u / -s 'ChunkedEncodingSpecialTest'";
577 eval {
578 $result = NPTest->testCmd( $cmd, 5 );
579 };
580 is( $@, "", $cmd );
452} 581}
diff --git a/plugins/tests/check_procs.t b/plugins/tests/check_procs.t
index 54d43d9..b3a0a30 100755
--- a/plugins/tests/check_procs.t
+++ b/plugins/tests/check_procs.t
@@ -8,13 +8,14 @@ use Test::More;
8use NPTest; 8use NPTest;
9 9
10if (-x "./check_procs") { 10if (-x "./check_procs") {
11 plan tests => 50; 11 plan tests => 54;
12} else { 12} else {
13 plan skip_all => "No check_procs compiled"; 13 plan skip_all => "No check_procs compiled";
14} 14}
15 15
16my $result; 16my $result;
17my $command = "./check_procs --input-file=tests/var/ps-axwo.darwin"; 17my $command = "./check_procs --input-file=tests/var/ps-axwo.darwin";
18my $cmd_etime = "./check_procs --input-file=tests/var/ps-axwo.debian";
18 19
19$result = NPTest->testCmd( "$command" ); 20$result = NPTest->testCmd( "$command" );
20is( $result->return_code, 0, "Run with no options" ); 21is( $result->return_code, 0, "Run with no options" );
@@ -33,9 +34,13 @@ is( $result->return_code, 0, "Checking no threshold breeched" );
33is( $result->output, "PROCS OK: 95 processes | procs=95;100;200;0;", "Output correct" ); 34is( $result->output, "PROCS OK: 95 processes | procs=95;100;200;0;", "Output correct" );
34 35
35$result = NPTest->testCmd( "$command -C launchd -c 5" ); 36$result = NPTest->testCmd( "$command -C launchd -c 5" );
36is( $result->return_code, 2, "Checking processes filtered by command name" ); 37is( $result->return_code, 2, "Checking processes matched by command name" );
37is( $result->output, "PROCS CRITICAL: 6 processes with command name 'launchd' | procs=6;;5;0;", "Output correct" ); 38is( $result->output, "PROCS CRITICAL: 6 processes with command name 'launchd' | procs=6;;5;0;", "Output correct" );
38 39
40$result = NPTest->testCmd( "$command -X bash -c 5" );
41is( $result->return_code, 2, "Checking processes excluded by command name" );
42is( $result->output, "PROCS CRITICAL: 95 processes with exclude progs 'bash' | procs=95;;5;0;", "Output correct" );
43
39SKIP: { 44SKIP: {
40 skip 'user with uid 501 required', 4 unless getpwuid(501); 45 skip 'user with uid 501 required', 4 unless getpwuid(501);
41 46
@@ -69,9 +74,21 @@ SKIP: {
69 like( $result->output, '/^PROCS OK: 0 processes with UID = -2 \(nobody\), args \'UsB\'/', "Output correct" ); 74 like( $result->output, '/^PROCS OK: 0 processes with UID = -2 \(nobody\), args \'UsB\'/', "Output correct" );
70}; 75};
71 76
72$result = NPTest->testCmd( "$command --ereg-argument-array='mdworker.*501'" ); 77SKIP: {
73is( $result->return_code, 0, "Checking regexp search of arguments" ); 78 skip 'check_procs is compiled with etime format support', 2 if `$command -vvv` =~ m/etime/mx;
74is( $result->output, "PROCS OK: 1 process with regex args 'mdworker.*501' | procs=1;;;0;", "Output correct" ); 79
80 $result = NPTest->testCmd( "$command --ereg-argument-array='mdworker.*501'" );
81 is( $result->return_code, 0, "Checking regexp search of arguments" );
82 is( $result->output, "PROCS OK: 1 process with regex args 'mdworker.*501' | procs=1;;;0;", "Output correct" );
83}
84
85SKIP: {
86 skip 'check_procs is compiled without etime format support', 2 if `$cmd_etime -vvv` !~ m/etime/mx;
87
88 $result = NPTest->testCmd( "$cmd_etime -m ELAPSED -C apache2 -w 1000 -c 2000" );
89 is( $result->return_code, 2, "Checking elapsed time threshold" );
90 is( $result->output, "ELAPSED CRITICAL: 10 crit, 0 warn out of 10 processes with command name 'apache2' | procs=10;;;0; procs_warn=0;;;0; procs_crit=10;;;0;", "Output correct" );
91}
75 92
76$result = NPTest->testCmd( "$command --vsz 1000000" ); 93$result = NPTest->testCmd( "$command --vsz 1000000" );
77is( $result->return_code, 0, "Checking filter by VSZ" ); 94is( $result->return_code, 0, "Checking filter by VSZ" );
@@ -83,7 +100,7 @@ is( $result->output, 'PROCS OK: 3 processes with RSS >= 100000 | procs=3;;;0;',
83 100
84$result = NPTest->testCmd( "$command -s S" ); 101$result = NPTest->testCmd( "$command -s S" );
85is( $result->return_code, 0, "Checking filter for sleeping processes" ); 102is( $result->return_code, 0, "Checking filter for sleeping processes" );
86like( $result->output, '/^PROCS OK: 44 processes with STATE = S/', "Output correct" ); 103like( $result->output, '/^PROCS OK: 88 processes with STATE = S/', "Output correct" );
87 104
88$result = NPTest->testCmd( "$command -s Z" ); 105$result = NPTest->testCmd( "$command -s Z" );
89is( $result->return_code, 0, "Checking filter for zombies" ); 106is( $result->return_code, 0, "Checking filter for zombies" );
@@ -129,4 +146,3 @@ is( $result->output, 'RSS CRITICAL: 5 crit, 0 warn out of 95 processes [WindowSe
129$result = NPTest->testCmd( "$command --ereg-argument-array='(nosuchname|nosuch2name)'" ); 146$result = NPTest->testCmd( "$command --ereg-argument-array='(nosuchname|nosuch2name)'" );
130is( $result->return_code, 0, "Checking no pipe symbol in output" ); 147is( $result->return_code, 0, "Checking no pipe symbol in output" );
131is( $result->output, "PROCS OK: 0 processes with regex args '(nosuchname,nosuch2name)' | procs=0;;;0;", "Output correct" ); 148is( $result->output, "PROCS OK: 0 processes with regex args '(nosuchname,nosuch2name)' | procs=0;;;0;", "Output correct" );
132
diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t
index 73a68b2..bfe42e1 100755
--- a/plugins/tests/check_snmp.t
+++ b/plugins/tests/check_snmp.t
@@ -7,8 +7,9 @@ use strict;
7use Test::More; 7use Test::More;
8use NPTest; 8use NPTest;
9use FindBin qw($Bin); 9use FindBin qw($Bin);
10use POSIX qw/strftime/;
10 11
11my $tests = 67; 12my $tests = 81;
12# Check that all dependent modules are available 13# Check that all dependent modules are available
13eval { 14eval {
14 require NetSNMP::OID; 15 require NetSNMP::OID;
@@ -37,6 +38,7 @@ if ($@) {
37 38
38my $port_snmp = 16100 + int(rand(100)); 39my $port_snmp = 16100 + int(rand(100));
39 40
41my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
40 42
41# Start up server 43# Start up server
42my @pids; 44my @pids;
@@ -51,13 +53,13 @@ if ($pid) {
51 #print "child\n"; 53 #print "child\n";
52 54
53 print "Please contact SNMP at: $port_snmp\n"; 55 print "Please contact SNMP at: $port_snmp\n";
54 close(STDERR); # Coment out to debug snmpd problems (most errors sent there are OK) 56 close(STDERR); # Comment out to debug snmpd problems (most errors sent there are OK)
55 exec("snmpd -c tests/conf/snmpd.conf -C -f -r udp:$port_snmp"); 57 exec("snmpd -c tests/conf/snmpd.conf -C -f -r udp:$port_snmp");
56} 58}
57 59
58END { 60END {
59 foreach my $pid (@pids) { 61 foreach my $pid (@pids) {
60 if ($pid) { print "Killing $pid\n"; kill "INT", $pid } 62 if ($pid) { print "Killing $pid\n"; kill "INT", $pid }
61 } 63 }
62}; 64};
63 65
@@ -118,77 +120,81 @@ like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C
118"And now have fun with with this: \"C:\\\\\" 120"And now have fun with with this: \"C:\\\\\"
119because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); 121because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3");
120 122
121system("rm -f ".$ENV{'MP_STATE_PATH'}."/check_snmp/*"); 123system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*");
122$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 --rate -w 600" );
123is($res->return_code, 0, "Returns OK");
124is($res->output, "No previous data to calculate rate - assume okay");
125 124
126# Need to sleep, otherwise duration=0 125# run rate checks with faketime. rate checks depend on the exact amount of time spend between the
127sleep 1; 126# plugin runs which may fail on busy machines.
127# using faketime removes this race condition and also saves all the sleeps in between.
128SKIP: {
129 skip "No faketime binary found", 28 if !$faketime;
128 130
129$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 --rate -w 600" ); 131 my $ts = time();
130is($res->return_code, 1, "WARNING - due to going above rate calculation" ); 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" );
131is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 "); 133 is($res->return_code, 0, "Returns OK");
134 is($res->output, "No previous data to calculate rate - assume okay");
132 135
133$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 --rate -w 600" ); 136 # test rate 1 second later
134is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); 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" );
135is($res->output, "Time duration between plugin calls is invalid"); 138 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 ");
136 140
141 # 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" );
143 is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" );
144 is($res->output, "Time duration between plugin calls is invalid");
137 145
138$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 --rate -l inoctets" );
139is($res->return_code, 0, "OK for first call" );
140is($res->output, "No previous data to calculate rate - assume okay" );
141 146
142# Need to sleep, otherwise duration=0 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" );
143sleep 1; 148 is($res->return_code, 0, "OK for first call" );
149 is($res->output, "No previous data to calculate rate - assume okay" );
144 150
145$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 --rate -l inoctets" ); 151 # test rate 1 second later
146is($res->return_code, 0, "OK as no thresholds" ); 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" );
147is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label"); 153 is($res->return_code, 0, "OK as no thresholds" );
154 is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label");
148 155
149sleep 2; 156 # 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" );
158 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");
150 160
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 --rate -l inoctets" );
152is($res->return_code, 0, "OK as no thresholds" );
153is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval");
154 161
162 # 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" );
164 is($res->return_code, 0, "OK as no thresholds" );
165 is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label");
155 166
156# label performance data check 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\"" );
157$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" ); 168 is($res->return_code, 0, "OK as no thresholds" );
158is($res->return_code, 0, "OK as no thresholds" ); 169 is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label");
159is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label");
160 170
161$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\"" ); 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'" );
162is($res->return_code, 0, "OK as no thresholds" ); 172 is($res->return_code, 0, "OK as no thresholds" );
163is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label"); 173 is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label");
164 174
165$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'" ); 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" );
166is($res->return_code, 0, "OK as no thresholds" ); 176 is($res->return_code, 0, "OK as no thresholds" );
167is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label"); 177 is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label");
168 178
169$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" ); 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" );
170is($res->return_code, 0, "OK as no thresholds" ); 180 is($res->return_code, 0, "OK as no thresholds" );
171is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label"); 181 is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label");
172 182
173$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" ); 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'" );
174is($res->return_code, 0, "OK as no thresholds" ); 184 is($res->return_code, 0, "OK as no thresholds" );
175is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label"); 185 is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label");
176 186
177$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'" );
178is($res->return_code, 0, "OK as no thresholds" );
179is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label");
180 187
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" );
189 is($res->return_code, 0, "OK for first call" );
190 is($res->output, "No previous data to calculate rate - assume okay" );
181 191
182$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 --rate -l inoctets_per_minute --rate-multiplier=60" ); 192 # test 1 second later
183is($res->return_code, 0, "OK for first call" ); 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" );
184is($res->output, "No previous data to calculate rate - assume okay" ); 194 is($res->return_code, 0, "OK as no thresholds" );
185 195 is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier");
186# Need to sleep, otherwise duration=0 196};
187sleep 1;
188 197
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.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
190is($res->return_code, 0, "OK as no thresholds" );
191is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier");
192 198
193 199
194$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\"'" ); 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\"'" );
@@ -221,7 +227,7 @@ is($res->output, 'SNMP OK - "555\"I said\"" | ', "Check string with a double quo
221 227
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.15 -r 'CUSTOM CHECK OK'" ); 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'" );
223is($res->return_code, 0, "String check should check whole string, not a parsed number" ); 229is($res->return_code, 0, "String check should check whole string, not a parsed number" );
224is($res->output, 'SNMP OK - "CUSTOM CHECK OK: foo is 12345" | ', "String check witn numbers returns whole string"); 230is($res->output, 'SNMP OK - "CUSTOM CHECK OK: foo is 12345" | ', "String check with numbers returns whole string");
225 231
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:" ); 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:" );
227is($res->return_code, 0, "Negative integer check OK" ); 233is($res->return_code, 0, "Negative integer check OK" );
@@ -245,9 +251,36 @@ is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3:
245 251
246$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'" ); 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'" );
247is($res->return_code, 0, "Negative float OK" ); 253is($res->return_code, 0, "Negative float OK" );
248is($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" ); 254is($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" );
249 255
250$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'" ); 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'" );
251is($res->return_code, 1, "Negative float WARNING" ); 257is($res->return_code, 1, "Negative float WARNING" );
252is($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" ); 258is($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" );
259
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'" );
261is($res->return_code, 0, "Multiple OIDs with thresholds" );
262like($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" );
263
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'" );
265is($res->return_code, 1, "Multiple OIDs with thresholds" );
266like($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" );
267
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" );
269is($res->return_code, 2, "Multiple OIDs with some thresholds" );
270like($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" );
271
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");
273is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" );
274is($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" );
275
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");
277is($res->return_code, 0, "Test multiply RC" );
278is($res->output,'SNMP OK - 4.200000 | iso.3.6.1.4.1.8072.3.2.67.19=4.200000 ' , "Test multiply .1 output" );
279
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' ");
281is($res->return_code, 0, "Test multiply RC + format" );
282is($res->output, 'SNMP OK - 4.20 | iso.3.6.1.4.1.8072.3.2.67.19=4.20 ', "Test multiply .1 output + format" );
253 283
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");
285is($res->return_code, 1, "Test multiply RC + format + thresholds" );
286is($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" );
diff --git a/plugins/tests/check_snmp_agent.pl b/plugins/tests/check_snmp_agent.pl
index 0e41d57..38912e9 100644
--- a/plugins/tests/check_snmp_agent.pl
+++ b/plugins/tests/check_snmp_agent.pl
@@ -32,11 +32,11 @@ my $multilin5 = 'And now have fun with with this: "C:\\"
32because we\'re not done yet!'; 32because we\'re not done yet!';
33 33
34# Next are arrays of indexes (Type, initial value and increments) 34# Next are arrays of indexes (Type, initial value and increments)
35# 0..16 <---- please update comment when adding/removing fields 35# 0..19 <---- please update comment when adding/removing fields
36my @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 ); 36my @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 );
37my @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' ); 37my @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# undef increments are randomized 38# undef increments are randomized
39my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666, undef, undef, undef, undef, undef, -1, undef, undef ); 39my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666, undef, undef, undef, undef, undef, -1, undef, undef, 0 );
40 40
41# Number of elements in our OID 41# Number of elements in our OID
42my $oidelts; 42my $oidelts;
diff --git a/plugins/tests/var/ps-axwo.debian b/plugins/tests/var/ps-axwo.debian
new file mode 100644
index 0000000..5889e9a
--- /dev/null
+++ b/plugins/tests/var/ps-axwo.debian
@@ -0,0 +1,219 @@
1STAT UID PID PPID VSZ RSS %CPU ELAPSED COMMAND COMMAND
2Ss 0 1 0 167244 7144 0.1 26-03:07:26 systemd /lib/systemd/systemd --system --deserialize 17
3S 0 2 0 0 0 0.0 26-03:07:26 kthreadd [kthreadd]
4I< 0 3 2 0 0 0.0 26-03:07:26 rcu_gp [rcu_gp]
5I< 0 4 2 0 0 0.0 26-03:07:26 rcu_par_gp [rcu_par_gp]
6I< 0 6 2 0 0 0.0 26-03:07:26 kworker/0:0H-ev [kworker/0:0H-events_highpri]
7I< 0 9 2 0 0 0.0 26-03:07:26 mm_percpu_wq [mm_percpu_wq]
8S 0 10 2 0 0 0.0 26-03:07:26 rcu_tasks_rude_ [rcu_tasks_rude_]
9S 0 11 2 0 0 0.0 26-03:07:26 rcu_tasks_trace [rcu_tasks_trace]
10S 0 12 2 0 0 0.0 26-03:07:26 ksoftirqd/0 [ksoftirqd/0]
11I 0 13 2 0 0 0.0 26-03:07:26 rcu_sched [rcu_sched]
12S 0 14 2 0 0 0.0 26-03:07:26 migration/0 [migration/0]
13S 0 15 2 0 0 0.0 26-03:07:26 cpuhp/0 [cpuhp/0]
14S 0 16 2 0 0 0.0 26-03:07:26 cpuhp/1 [cpuhp/1]
15S 0 17 2 0 0 0.0 26-03:07:26 migration/1 [migration/1]
16S 0 18 2 0 0 0.0 26-03:07:26 ksoftirqd/1 [ksoftirqd/1]
17I< 0 20 2 0 0 0.0 26-03:07:26 kworker/1:0H-ev [kworker/1:0H-events_highpri]
18S 0 21 2 0 0 0.0 26-03:07:26 cpuhp/2 [cpuhp/2]
19S 0 22 2 0 0 0.0 26-03:07:26 migration/2 [migration/2]
20S 0 23 2 0 0 0.0 26-03:07:26 ksoftirqd/2 [ksoftirqd/2]
21I< 0 25 2 0 0 0.0 26-03:07:26 kworker/2:0H-ev [kworker/2:0H-events_highpri]
22S 0 26 2 0 0 0.0 26-03:07:26 cpuhp/3 [cpuhp/3]
23S 0 27 2 0 0 0.0 26-03:07:26 migration/3 [migration/3]
24S 0 28 2 0 0 0.0 26-03:07:26 ksoftirqd/3 [ksoftirqd/3]
25I< 0 30 2 0 0 0.0 26-03:07:26 kworker/3:0H-ev [kworker/3:0H-events_highpri]
26S 0 35 2 0 0 0.0 26-03:07:26 kdevtmpfs [kdevtmpfs]
27I< 0 36 2 0 0 0.0 26-03:07:26 netns [netns]
28S 0 37 2 0 0 0.0 26-03:07:26 kauditd [kauditd]
29S 0 38 2 0 0 0.0 26-03:07:26 khungtaskd [khungtaskd]
30S 0 39 2 0 0 0.0 26-03:07:26 oom_reaper [oom_reaper]
31I< 0 40 2 0 0 0.0 26-03:07:26 writeback [writeback]
32S 0 41 2 0 0 0.0 26-03:07:26 kcompactd0 [kcompactd0]
33SN 0 42 2 0 0 0.0 26-03:07:26 ksmd [ksmd]
34SN 0 43 2 0 0 0.0 26-03:07:26 khugepaged [khugepaged]
35I< 0 62 2 0 0 0.0 26-03:07:26 kintegrityd [kintegrityd]
36I< 0 63 2 0 0 0.0 26-03:07:26 kblockd [kblockd]
37I< 0 64 2 0 0 0.0 26-03:07:26 blkcg_punt_bio [blkcg_punt_bio]
38I< 0 65 2 0 0 0.0 26-03:07:26 edac-poller [edac-poller]
39I< 0 66 2 0 0 0.0 26-03:07:26 devfreq_wq [devfreq_wq]
40I< 0 67 2 0 0 0.0 26-03:07:26 kworker/2:1H-ev [kworker/2:1H-events_highpri]
41S 0 70 2 0 0 0.3 26-03:07:25 kswapd0 [kswapd0]
42I< 0 71 2 0 0 0.0 26-03:07:25 kthrotld [kthrotld]
43I< 0 72 2 0 0 0.0 26-03:07:25 acpi_thermal_pm [acpi_thermal_pm]
44I< 0 74 2 0 0 0.0 26-03:07:25 ipv6_addrconf [ipv6_addrconf]
45I< 0 80 2 0 0 0.0 26-03:07:25 kworker/3:1H-ev [kworker/3:1H-events_highpri]
46I< 0 84 2 0 0 0.0 26-03:07:25 kstrp [kstrp]
47I< 0 87 2 0 0 0.0 26-03:07:25 zswap-shrink [zswap-shrink]
48I< 0 110 2 0 0 0.0 26-03:07:25 kworker/0:1H-ev [kworker/0:1H-events_highpri]
49I< 0 141 2 0 0 0.0 26-03:07:25 ata_sff [ata_sff]
50S 0 143 2 0 0 0.0 26-03:07:25 scsi_eh_0 [scsi_eh_0]
51I< 0 144 2 0 0 0.0 26-03:07:25 scsi_tmf_0 [scsi_tmf_0]
52S 0 145 2 0 0 0.0 26-03:07:25 scsi_eh_1 [scsi_eh_1]
53I< 0 146 2 0 0 0.0 26-03:07:25 scsi_tmf_1 [scsi_tmf_1]
54S 0 147 2 0 0 0.0 26-03:07:25 scsi_eh_2 [scsi_eh_2]
55I< 0 148 2 0 0 0.0 26-03:07:25 scsi_tmf_2 [scsi_tmf_2]
56S 0 149 2 0 0 0.0 26-03:07:25 scsi_eh_3 [scsi_eh_3]
57I< 0 150 2 0 0 0.0 26-03:07:25 scsi_tmf_3 [scsi_tmf_3]
58S 0 151 2 0 0 0.0 26-03:07:25 scsi_eh_4 [scsi_eh_4]
59I< 0 152 2 0 0 0.0 26-03:07:25 scsi_tmf_4 [scsi_tmf_4]
60S 0 153 2 0 0 0.0 26-03:07:25 scsi_eh_5 [scsi_eh_5]
61I< 0 154 2 0 0 0.0 26-03:07:25 scsi_tmf_5 [scsi_tmf_5]
62S 0 158 2 0 0 0.0 26-03:07:25 card0-crtc0 [card0-crtc0]
63S 0 159 2 0 0 0.0 26-03:07:25 card0-crtc1 [card0-crtc1]
64S 0 160 2 0 0 0.0 26-03:07:25 card0-crtc2 [card0-crtc2]
65I< 0 162 2 0 0 0.0 26-03:07:25 kworker/1:1H-ev [kworker/1:1H-events_highpri]
66S 0 163 2 0 0 0.0 26-03:07:25 scsi_eh_6 [scsi_eh_6]
67I< 0 164 2 0 0 0.0 26-03:07:25 scsi_tmf_6 [scsi_tmf_6]
68S 0 165 2 0 0 0.0 26-03:07:25 usb-storage [usb-storage]
69I< 0 167 2 0 0 0.0 26-03:07:25 uas [uas]
70I< 0 176 2 0 0 0.0 26-03:07:25 kdmflush [kdmflush]
71I< 0 177 2 0 0 0.0 26-03:07:25 kdmflush [kdmflush]
72S 0 202 2 0 0 0.0 26-03:07:24 scsi_eh_7 [scsi_eh_7]
73I< 0 203 2 0 0 0.0 26-03:07:24 scsi_tmf_7 [scsi_tmf_7]
74S 0 204 2 0 0 0.0 26-03:07:24 usb-storage [usb-storage]
75I< 0 232 2 0 0 0.0 26-03:07:23 btrfs-worker [btrfs-worker]
76I< 0 233 2 0 0 0.0 26-03:07:23 btrfs-worker-hi [btrfs-worker-hi]
77I< 0 234 2 0 0 0.0 26-03:07:23 btrfs-delalloc [btrfs-delalloc]
78I< 0 235 2 0 0 0.0 26-03:07:23 btrfs-flush_del [btrfs-flush_del]
79I< 0 236 2 0 0 0.0 26-03:07:23 btrfs-cache [btrfs-cache]
80I< 0 237 2 0 0 0.0 26-03:07:23 btrfs-fixup [btrfs-fixup]
81I< 0 238 2 0 0 0.0 26-03:07:23 btrfs-endio [btrfs-endio]
82I< 0 239 2 0 0 0.0 26-03:07:23 btrfs-endio-met [btrfs-endio-met]
83I< 0 240 2 0 0 0.0 26-03:07:23 btrfs-endio-met [btrfs-endio-met]
84I< 0 241 2 0 0 0.0 26-03:07:23 btrfs-endio-rai [btrfs-endio-rai]
85I< 0 242 2 0 0 0.0 26-03:07:23 btrfs-rmw [btrfs-rmw]
86I< 0 243 2 0 0 0.0 26-03:07:23 btrfs-endio-wri [btrfs-endio-wri]
87I< 0 244 2 0 0 0.0 26-03:07:23 btrfs-freespace [btrfs-freespace]
88I< 0 245 2 0 0 0.0 26-03:07:23 btrfs-delayed-m [btrfs-delayed-m]
89I< 0 246 2 0 0 0.0 26-03:07:23 btrfs-readahead [btrfs-readahead]
90I< 0 247 2 0 0 0.0 26-03:07:23 btrfs-qgroup-re [btrfs-qgroup-re]
91S 0 248 2 0 0 0.0 26-03:07:23 btrfs-cleaner [btrfs-cleaner]
92S 0 249 2 0 0 0.2 26-03:07:23 btrfs-transacti [btrfs-transacti]
93I< 0 317 2 0 0 0.0 26-03:07:22 rpciod [rpciod]
94I< 0 322 2 0 0 0.0 26-03:07:22 xprtiod [xprtiod]
95S 0 381 2 0 0 0.0 26-03:07:22 irq/133-mei_me [irq/133-mei_me]
96S 0 422 2 0 0 0.0 26-03:07:22 watchdogd [watchdogd]
97I< 0 523 2 0 0 0.0 26-03:07:22 led_workqueue [led_workqueue]
98I< 0 583 2 0 0 0.0 26-03:07:22 cryptd [cryptd]
99I< 0 590 2 0 0 0.0 26-03:07:22 ext4-rsv-conver [ext4-rsv-conver]
100Ss 104 693 1 12324 4292 0.5 26-03:07:21 dbus-daemon /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
101Ss 0 731 1 575120 1368 0.0 26-03:07:21 systemd-logind /lib/systemd/systemd-logind
102Ssl 0 1111 1 121248 732 0.0 26-03:07:18 unattended-upgr /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
103S 0 1141 2 0 0 0.0 26-03:07:18 lockd [lockd]
104I< 0 1459 2 0 0 0.0 26-03:07:16 nfsiod [nfsiod]
105S 0 1621 2 0 0 0.0 26-03:07:15 NFSv4 callback [NFSv4 callback]
106Ssl 0 1771 1 1548340 676 0.0 26-03:07:13 libvirtd /usr/sbin/libvirtd
107I< 0 24315 2 0 0 0.0 26-02:49:02 cifsiod [cifsiod]
108I< 0 24316 2 0 0 0.0 26-02:49:02 smb3decryptd [smb3decryptd]
109I< 0 24317 2 0 0 0.0 26-02:49:02 cifsfileinfoput [cifsfileinfoput]
110I< 0 24318 2 0 0 0.0 26-02:49:02 cifsoplockd [cifsoplockd]
111I< 0 24319 2 0 0 0.0 26-02:49:02 cifs-dfscache [cifs-dfscache]
112S 0 24322 2 0 0 0.0 26-02:49:02 cifsd [cifsd]
113I< 0 24413 2 0 0 0.0 26-02:48:57 btrfs-worker [btrfs-worker]
114I< 0 24414 2 0 0 0.0 26-02:48:57 btrfs-worker-hi [btrfs-worker-hi]
115I< 0 24415 2 0 0 0.0 26-02:48:57 btrfs-delalloc [btrfs-delalloc]
116I< 0 24416 2 0 0 0.0 26-02:48:57 btrfs-flush_del [btrfs-flush_del]
117I< 0 24418 2 0 0 0.0 26-02:48:57 btrfs-cache [btrfs-cache]
118I< 0 24419 2 0 0 0.0 26-02:48:57 btrfs-fixup [btrfs-fixup]
119I< 0 24420 2 0 0 0.0 26-02:48:57 btrfs-endio [btrfs-endio]
120I< 0 24421 2 0 0 0.0 26-02:48:57 btrfs-endio-met [btrfs-endio-met]
121I< 0 24422 2 0 0 0.0 26-02:48:57 btrfs-endio-met [btrfs-endio-met]
122I< 0 24423 2 0 0 0.0 26-02:48:57 btrfs-endio-rai [btrfs-endio-rai]
123I< 0 24424 2 0 0 0.0 26-02:48:57 btrfs-rmw [btrfs-rmw]
124I< 0 24425 2 0 0 0.0 26-02:48:57 btrfs-endio-wri [btrfs-endio-wri]
125I< 0 24426 2 0 0 0.0 26-02:48:57 btrfs-freespace [btrfs-freespace]
126I< 0 24427 2 0 0 0.0 26-02:48:57 btrfs-delayed-m [btrfs-delayed-m]
127I< 0 24428 2 0 0 0.0 26-02:48:57 btrfs-readahead [btrfs-readahead]
128I< 0 24429 2 0 0 0.0 26-02:48:57 btrfs-qgroup-re [btrfs-qgroup-re]
129S 0 24450 2 0 0 0.0 26-02:48:53 btrfs-cleaner [btrfs-cleaner]
130S 0 24451 2 0 0 0.0 26-02:48:53 btrfs-transacti [btrfs-transacti]
131I< 0 747708 2 0 0 0.0 16-21:06:20 xfsalloc [xfsalloc]
132I< 0 747709 2 0 0 0.0 16-21:06:20 xfs_mru_cache [xfs_mru_cache]
133S 0 747713 2 0 0 0.0 16-21:06:20 jfsIO [jfsIO]
134S 0 747714 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
135S 0 747715 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
136S 0 747716 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
137S 0 747717 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
138S 0 747718 2 0 0 0.0 16-21:06:20 jfsSync [jfsSync]
139Ss 0 1071687 1 105976 28304 0.0 3-03:12:31 systemd-journal /lib/systemd/systemd-journald
140Ss 0 1934146 1 25672 4704 0.0 11:19:31 cupsd /usr/sbin/cupsd -l
141Ssl 0 1934148 1 182868 8540 0.0 11:19:31 cups-browsed /usr/sbin/cups-browsed
142S 13 1934155 3392655 5752 88 0.0 11:19:31 pinger (pinger)
143S< 33 1934166 3393034 57996 5460 0.0 11:19:31 apache2 /usr/sbin/apache2 -k start
144S< 33 1934167 3393034 216944 13892 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
145S< 33 1934168 3393034 216944 13756 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
146S< 33 1934169 3393034 216936 13732 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
147S< 33 1934170 3393034 216944 13888 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
148S< 33 1934172 3393034 216944 15388 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
149S< 33 1934701 3393034 216936 13736 0.0 11:19:29 apache2 /usr/sbin/apache2 -k start
150S< 33 1935056 3393034 216920 13724 0.0 11:19:28 apache2 /usr/sbin/apache2 -k start
151S 7 1936834 1934146 16652 832 0.0 11:18:12 dbus /usr/lib/cups/notifier/dbus dbus://
152S< 33 1955909 3393034 216928 13792 0.0 11:00:25 apache2 /usr/sbin/apache2 -k start
153I< 0 2531464 2 0 0 0.0 06:35:47 kworker/u9:0-i9 [kworker/u9:0-i915_flip]
154I 0 2570506 2 0 0 0.0 06:27:41 kworker/1:0-cgr [kworker/1:0-cgroup_destroy]
155I 0 2596195 2 0 0 0.0 06:21:52 kworker/1:1-eve [kworker/1:1-events]
156I 0 2785341 2 0 0 0.0 03:34:16 kworker/u8:8-bt [kworker/u8:8-btrfs-endio-write]
157I 0 2785520 2 0 0 0.0 03:33:50 kworker/3:0-eve [kworker/3:0-events]
158I 0 2798669 2 0 0 0.0 03:21:09 kworker/u8:5-bt [kworker/u8:5-btrfs-endio-write]
159Ss 0 2803015 1 5616 3108 0.0 03:17:54 cron /usr/sbin/cron -f
160I 0 2845483 2 0 0 0.0 02:38:11 kworker/0:3-eve [kworker/0:3-events]
161I 0 2939490 2 0 0 0.1 01:10:32 kworker/0:0-eve [kworker/0:0-events]
162I 0 2939754 2 0 0 0.0 01:10:26 kworker/u8:1-i9 [kworker/u8:1-i915]
163I 0 2942040 2 0 0 0.0 01:08:02 kworker/u8:7-bt [kworker/u8:7-btrfs-endio-meta]
164S 117 2954268 3392551 40044 5772 0.0 56:37 pickup pickup -l -t unix -u -c
165I 0 2965195 2 0 0 0.0 46:00 kworker/u8:0-bt [kworker/u8:0-btrfs-worker]
166I 0 2977972 2 0 0 0.0 33:54 kworker/u8:2-bt [kworker/u8:2-btrfs-endio-write]
167I 0 2985488 2 0 0 0.0 27:02 kworker/u8:3-bl [kworker/u8:3-blkcg_punt_bio]
168I 0 2987519 2 0 0 1.0 25:15 kworker/2:1-eve [kworker/2:1-events]
169I 0 2987601 2 0 0 0.0 25:03 kworker/u8:9-i9 [kworker/u8:9-i915]
170I< 0 2995218 2 0 0 0.0 18:41 kworker/u9:2-xp [kworker/u9:2-xprtiod]
171I 0 2997170 2 0 0 0.0 16:41 kworker/3:1-rcu [kworker/3:1-rcu_gp]
172I 0 3001264 2 0 0 0.0 13:01 kworker/u8:4-bt [kworker/u8:4-btrfs-endio-write]
173I 0 3004697 2 0 0 0.7 09:41 kworker/2:0-eve [kworker/2:0-events]
174I 0 3010619 2 0 0 1.0 04:29 kworker/2:2-eve [kworker/2:2-events]
175I 0 3014612 2 0 0 0.0 00:41 kworker/3:2-eve [kworker/3:2-events]
176S 0 3015082 2803015 6716 3028 0.0 00:30 cron /usr/sbin/CRON -f
177I 0 3015382 2 0 0 0.0 00:00 kworker/u8:6-bt [kworker/u8:6-btrfs-endio-meta]
178Ss 1 3392068 1 5592 504 0.0 15-02:34:39 atd /usr/sbin/atd -f
179Ssl 0 3392072 1 235796 1740 0.0 15-02:34:39 accounts-daemon /usr/libexec/accounts-daemon
180Ssl 106 3392076 1 315708 6128 0.0 15-02:34:39 colord /usr/libexec/colord
181Ss 0 3392083 1 8120 720 0.0 15-02:34:39 haveged /usr/sbin/haveged --Foreground --verbose=1
182Ss 0 3392090 1 5168 132 0.0 15-02:34:39 blkmapd /usr/sbin/blkmapd
183SNsl 111 3392094 1 155648 440 0.0 15-02:34:39 rtkit-daemon /usr/libexec/rtkit-daemon
184Ssl 0 3392097 1 290168 1352 0.0 15-02:34:39 packagekitd /usr/libexec/packagekitd
185Ss 128 3392100 1 7960 448 0.0 15-02:34:39 rpcbind /sbin/rpcbind -f -w
186Ss 0 3392114 1 13432 616 0.0 15-02:34:39 systemd-machine /lib/systemd/systemd-machined
187Ss 0 3392118 1 13316 848 0.0 15-02:34:39 sshd sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
188Ssl 0 3392124 1 244072 2456 0.0 15-02:34:39 upowerd /usr/libexec/upowerd
189Ssl 0 3392138 1 1634748 10684 0.0 15-02:34:39 containerd /usr/bin/containerd
190Ssl 0 3392139 1 222768 1784 0.0 15-02:34:39 rsyslogd /usr/sbin/rsyslogd -n -iNONE
191Ss 13 3392140 1 3344 152 0.0 15-02:34:39 polipo /usr/bin/polipo -c /etc/polipo/config pidFile=/var/run/polipo/polipo.pid daemonise=true
192Ssl 119 3392156 1 76472 1688 0.0 15-02:34:39 ntpd /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 119:126
193Ss 120 3392168 1 4656 276 0.0 15-02:34:39 rpc.statd /sbin/rpc.statd --no-notify
194Ss 0 3392171 1 5072 432 0.0 15-02:34:39 rpc.mountd /usr/sbin/rpc.mountd --manage-gids
195Ss 0 3392176 1 5008 288 0.0 15-02:34:39 rpc.idmapd /usr/sbin/rpc.idmapd
196Ss 105 3392184 1 15544 6816 3.5 15-02:34:39 avahi-daemon avahi-daemon: running [tsui.local]
197Ss 0 3392186 1 25288 3860 0.0 15-02:34:39 systemd-udevd /lib/systemd/systemd-udevd
198S 105 3392190 3392184 8788 52 0.0 15-02:34:39 avahi-daemon avahi-daemon: chroot helper
199Ssl 0 3392197 1 396120 4188 0.0 15-02:34:39 udisksd /usr/libexec/udisks2/udisksd
200Ssl 0 3392214 1 237504 6632 0.0 15-02:34:39 polkitd /usr/libexec/polkitd --no-debug
201Ss 0 3392284 1 9684 560 0.0 15-02:34:38 xinetd /usr/sbin/xinetd -pidfile /run/xinetd.pid -stayalive -inetd_compat -inetd_ipv6
202Ssl 0 3392285 1 314840 1352 0.0 15-02:34:38 ModemManager /usr/sbin/ModemManager
203Ss 0 3392317 1 2352 140 0.0 15-02:34:38 acpid /usr/sbin/acpid
204S 0 3392400 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
205S 0 3392401 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
206S 0 3392402 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
207S 0 3392403 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
208S 0 3392404 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
209S 0 3392405 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
210S 0 3392407 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
211S 0 3392410 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
212Ss 0 3392551 1 40092 1304 0.0 15-02:34:37 master /usr/lib/postfix/sbin/master -w
213S 117 3392553 3392551 40156 568 0.0 15-02:34:37 qmgr qmgr -l -t unix -u
214Ss 0 3392650 1 63652 4 0.0 15-02:34:36 squid /usr/sbin/squid --foreground -sYC
215Ssl 116 3392652 1 1675196 93848 0.0 15-02:34:36 mariadbd /usr/sbin/mariadbd
216S 13 3392655 3392650 81776 21232 0.0 15-02:34:36 squid (squid-1) --kid squid-1 --foreground -sYC
217S 13 3392657 3392655 5572 68 0.0 15-02:34:36 log_file_daemon (logfile-daemon) /var/log/squid/access.log
218S<s 0 3393034 1 216648 7560 0.0 15-02:34:34 apache2 /usr/sbin/apache2 -k start
219Ss 33 3393037 1 3432 180 0.0 15-02:34:34 htcacheclean /usr/bin/htcacheclean -d 120 -p /var/cache/apache2/mod_cache_disk -l 300M -n
diff --git a/plugins/tests/var/ps_axwo.debian b/plugins/tests/var/ps_axwo.debian
deleted file mode 100644
index 37a2d35..0000000
--- a/plugins/tests/var/ps_axwo.debian
+++ /dev/null
@@ -1,84 +0,0 @@
1STAT UID PID PPID VSZ RSS %CPU COMMAND COMMAND
2S 0 1 0 1504 428 0.0 init init [2]
3SN 0 2 1 0 0 0.0 ksoftirqd/0 [ksoftirqd/0]
4S< 0 3 1 0 0 0.0 events/0 [events/0]
5S< 0 4 3 0 0 0.0 khelper [khelper]
6S< 0 5 3 0 0 0.0 kacpid [kacpid]
7S< 0 38 3 0 0 0.0 kblockd/0 [kblockd/0]
8S 0 48 3 0 0 0.0 pdflush [pdflush]
9S< 0 51 3 0 0 0.0 aio/0 [aio/0]
10S 0 50 1 0 0 0.0 kswapd0 [kswapd0]
11S 0 193 1 0 0 0.0 kseriod [kseriod]
12S 0 214 1 0 0 0.0 scsi_eh_0 [scsi_eh_0]
13S 0 221 1 0 0 0.0 khubd [khubd]
14S 0 299 1 0 0 0.3 kjournald [kjournald]
15S 0 1148 1 0 0 0.0 pciehpd_event [pciehpd_event]
16S 0 1168 1 0 0 0.0 shpchpd_event [shpchpd_event]
17Ss 1 1795 1 1612 276 0.0 portmap /sbin/portmap
18Ss 0 2200 1 1652 568 0.0 vmware-guestd /usr/sbin/vmware-guestd --background /var/run/vmware-guestd.pid
19Ss 0 2209 1 2240 532 0.0 inetd /usr/sbin/inetd
20Ss 0 2319 1 3468 792 0.0 sshd /usr/sbin/sshd
21Ss 0 2323 1 2468 676 0.0 rpc.statd /sbin/rpc.statd
22Ss 1 2332 1 1684 488 0.0 atd /usr/sbin/atd
23Ss 0 2335 1 1764 636 0.0 cron /usr/sbin/cron
24Ss+ 0 2350 1 1500 348 0.0 getty /sbin/getty 38400 tty1
25Ss+ 0 2351 1 1500 348 0.0 getty /sbin/getty 38400 tty2
26Ss+ 0 2352 1 1500 348 0.0 getty /sbin/getty 38400 tty3
27Ss+ 0 2353 1 1500 348 0.0 getty /sbin/getty 38400 tty4
28Ss+ 0 2354 1 1500 348 0.0 getty /sbin/getty 38400 tty5
29Ss+ 0 2355 1 1500 348 0.0 getty /sbin/getty 38400 tty6
30S 0 6907 1 2308 892 0.0 mysqld_safe /bin/sh /usr/bin/mysqld_safe
31S 103 6944 6907 123220 27724 0.0 mysqld /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --pid-file=/var/run/mysqld/mysqld.pid --skip-locking --port=3306 --socket=/var/run/mysqld/mysqld.sock
32S 0 6945 6907 1488 420 0.0 logger logger -p daemon.err -t mysqld_safe -i -t mysqld
33S 1001 17778 1 6436 1588 0.0 snmpd /usr/sbin/snmpd -u nagios -Lsd -Lf /dev/null -p/var/run/snmpd.pid
34Ss 0 17789 1 9496 5556 0.0 snmptrapd /usr/sbin/snmptrapd -t -m ALL -M /usr/share/snmp/mibs:/usr/local/monitoring/snmp/load -p /var/run/snmptrapd.pid
35Ss 0 847 2319 14452 1752 0.0 sshd sshd: tonvoon [priv]
36S 1000 857 847 14616 1832 0.0 sshd sshd: tonvoon@pts/3
37Ss 1000 860 857 2984 1620 0.0 bash -bash
38S 0 868 860 2588 1428 0.0 bash -su
39S+ 1001 877 868 2652 1568 0.0 bash -su
40S 0 6086 3 0 0 0.0 pdflush [pdflush]
41Ss 0 17832 2319 14452 1752 0.0 sshd sshd: tonvoon [priv]
42S 1000 18155 17832 14620 1840 0.0 sshd sshd: tonvoon@pts/0
43Ss 1000 18156 18155 2984 1620 0.0 bash -bash
44S 0 18518 18156 2588 1428 0.0 bash -su
45S 1001 18955 18518 2672 1600 0.0 bash -su
46Ss 0 21683 2319 14452 1756 0.0 sshd sshd: tonvoon [priv]
47S 1000 21742 21683 14620 1896 0.0 sshd sshd: tonvoon@pts/1
48Ss 1000 21743 21742 2984 1620 0.0 bash -bash
49S 0 21748 21743 2592 1432 0.0 bash -su
50S 1001 21757 21748 2620 1540 0.0 bash -su
51Ss 0 2334 2319 14452 1756 0.0 sshd sshd: tonvoon [priv]
52S 1000 2343 2334 14620 1840 0.0 sshd sshd: tonvoon@pts/2
53Ss 1000 2344 2343 2984 1620 0.0 bash -bash
54S 0 2349 2344 2592 1432 0.0 bash -su
55S+ 1001 2364 2349 2620 1520 0.0 bash -su
56T 1001 2454 2364 2096 1032 0.0 vi vi configure.in.rej
57S+ 1001 8500 21757 69604 52576 0.0 opsview_web_ser /usr/bin/perl -w ./script/opsview_web_server.pl -f -d
58Ss 0 7609 2319 14452 1756 0.0 sshd sshd: tonvoon [priv]
59S 1000 7617 7609 14460 1828 0.0 sshd sshd: tonvoon@pts/4
60Ss 1000 7618 7617 2984 1620 0.0 bash -bash
61S 0 7623 7618 2592 1432 0.0 bash -su
62S+ 1001 7632 7623 2620 1528 0.0 bash -su
63Ss 1001 12678 1 20784 17728 0.0 opsviewd opsviewd
64Ss 0 832 1 14512 6360 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
65S 33 842 832 14648 6596 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
66S 33 843 832 14512 6504 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
67S 33 844 832 14512 6476 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
68S 33 845 832 14512 6476 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
69S 33 846 832 14512 6476 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
70Ss 7 4081 1 2464 884 0.0 lpd /usr/sbin/lpd -s
71S 33 26484 832 14512 6476 0.0 apache2 /usr/sbin/apache2 -k start -DSSL
72Ss 1001 22324 1 20252 1612 0.1 nagios ../../bin/nagios -d /usr/local/nagios/etc/nagios.cfg
73Ss 0 23336 2319 14452 1756 0.0 sshd sshd: tonvoon [priv]
74S 1000 23339 23336 14620 1840 0.0 sshd sshd: tonvoon@pts/5
75Ss 1000 23340 23339 2996 1636 0.0 bash -bash
76S 0 23367 23340 3020 1628 0.0 bash bash
77S 1001 23370 23367 3064 1748 0.0 bash bash
78Ss 1001 23783 1 3220 764 0.0 ndo2db /usr/local/nagios/bin/ndo2db -c /usr/local/nagios/etc/ndo2db.cfg
79Ss 1001 23784 1 6428 4948 0.0 import_ndologsd import_ndologsd
80S+ 1001 9803 18955 4132 1936 0.0 ssh ssh altinity@cube02.lei.altinity
81S 1001 22505 22324 20256 1616 0.0 nagios ../../bin/nagios -d /usr/local/nagios/etc/nagios.cfg
82S 1001 22506 22505 1676 608 0.0 check_ping /usr/local/libexec/check_ping -H 192.168.10.23 -w 3000.0,80% -c 5000.0,100% -p 1
83S 1001 22507 22506 1660 492 0.0 ping /bin/ping -n -U -w 10 -c 1 192.168.10.23
84R+ 1001 22508 23370 2308 680 0.0 ps ps axwo stat uid pid ppid vsz rss pcpu comm args
diff --git a/plugins/utils.c b/plugins/utils.c
index 231af92..71c0bdd 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -27,6 +27,8 @@
27#include "utils_base.h" 27#include "utils_base.h"
28#include <stdarg.h> 28#include <stdarg.h>
29#include <limits.h> 29#include <limits.h>
30#include <string.h>
31#include <errno.h>
30 32
31#include <arpa/inet.h> 33#include <arpa/inet.h>
32 34
@@ -36,9 +38,6 @@ extern const char *progname;
36#define STRLEN 64 38#define STRLEN 64
37#define TXTBLK 128 39#define TXTBLK 128
38 40
39unsigned int timeout_state = STATE_CRITICAL;
40unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
41
42time_t start_time, end_time; 41time_t start_time, end_time;
43 42
44/* ************************************************************************** 43/* **************************************************************************
@@ -148,33 +147,6 @@ print_revision (const char *command_name, const char *revision)
148 command_name, revision, PACKAGE, VERSION); 147 command_name, revision, PACKAGE, VERSION);
149} 148}
150 149
151const char *
152state_text (int result)
153{
154 switch (result) {
155 case STATE_OK:
156 return "OK";
157 case STATE_WARNING:
158 return "WARNING";
159 case STATE_CRITICAL:
160 return "CRITICAL";
161 case STATE_DEPENDENT:
162 return "DEPENDENT";
163 default:
164 return "UNKNOWN";
165 }
166}
167
168void
169timeout_alarm_handler (int signo)
170{
171 if (signo == SIGALRM) {
172 printf (_("%s - Plugin timed out after %d seconds\n"),
173 state_text(timeout_state), timeout_interval);
174 exit (timeout_state);
175 }
176}
177
178int 150int
179is_numeric (char *number) 151is_numeric (char *number)
180{ 152{
@@ -269,6 +241,46 @@ is_intnonneg (char *number)
269 return FALSE; 241 return FALSE;
270} 242}
271 243
244/*
245 * Checks whether the number in the string _number_ can be put inside a int64_t
246 * On success the number will be written to the _target_ address, if _target_ is not set
247 * to NULL.
248 */
249int is_int64(char *number, int64_t *target) {
250 errno = 0;
251 uint64_t tmp = strtoll(number, NULL, 10);
252 if (errno != 0) {
253 return 0;
254 }
255 if (tmp < INT64_MIN || tmp > INT64_MAX) {
256 return 0;
257 }
258 if (target != NULL) {
259 *target = tmp;
260 }
261 return 1;
262}
263
264/*
265 * Checks whether the number in the string _number_ can be put inside a uint64_t
266 * On success the number will be written to the _target_ address, if _target_ is not set
267 * to NULL.
268 */
269int is_uint64(char *number, uint64_t *target) {
270 errno = 0;
271 uint64_t tmp = strtoll(number, NULL, 10);
272 if (errno != 0) {
273 return 0;
274 }
275 if (tmp < 0 || tmp > UINT64_MAX) {
276 return 0;
277 }
278 if (target != NULL) {
279 *target = tmp;
280 }
281 return 1;
282}
283
272int 284int
273is_intpercent (char *number) 285is_intpercent (char *number)
274{ 286{
@@ -577,10 +589,94 @@ char *perfdata (const char *label,
577 xasprintf (&data, "%s;", data); 589 xasprintf (&data, "%s;", data);
578 590
579 if (minp) 591 if (minp)
580 xasprintf (&data, "%s%ld", data, minv); 592 xasprintf (&data, "%s%ld;", data, minv);
593 else
594 xasprintf (&data, "%s;", data);
595
596 if (maxp)
597 xasprintf (&data, "%s%ld", data, maxv);
598
599 return data;
600}
601
602
603char *perfdata_uint64 (const char *label,
604 uint64_t val,
605 const char *uom,
606 int warnp, /* Warning present */
607 uint64_t warn,
608 int critp, /* Critical present */
609 uint64_t crit,
610 int minp, /* Minimum present */
611 uint64_t minv,
612 int maxp, /* Maximum present */
613 uint64_t maxv)
614{
615 char *data = NULL;
616
617 if (strpbrk (label, "'= "))
618 xasprintf (&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
619 else
620 xasprintf (&data, "%s=%" PRIu64 "%s;", label, val, uom);
621
622 if (warnp)
623 xasprintf (&data, "%s%" PRIu64 ";", data, warn);
624 else
625 xasprintf (&data, "%s;", data);
626
627 if (critp)
628 xasprintf (&data, "%s%" PRIu64 ";", data, crit);
629 else
630 xasprintf (&data, "%s;", data);
631
632 if (minp)
633 xasprintf (&data, "%s%" PRIu64 ";", data, minv);
634 else
635 xasprintf (&data, "%s;", data);
581 636
582 if (maxp) 637 if (maxp)
583 xasprintf (&data, "%s;%ld", data, maxv); 638 xasprintf (&data, "%s%" PRIu64, data, maxv);
639
640 return data;
641}
642
643
644char *perfdata_int64 (const char *label,
645 int64_t val,
646 const char *uom,
647 int warnp, /* Warning present */
648 int64_t warn,
649 int critp, /* Critical present */
650 int64_t crit,
651 int minp, /* Minimum present */
652 int64_t minv,
653 int maxp, /* Maximum present */
654 int64_t maxv)
655{
656 char *data = NULL;
657
658 if (strpbrk (label, "'= "))
659 xasprintf (&data, "'%s'=%" PRId64 "%s;", label, val, uom);
660 else
661 xasprintf (&data, "%s=%" PRId64 "%s;", label, val, uom);
662
663 if (warnp)
664 xasprintf (&data, "%s%" PRId64 ";", data, warn);
665 else
666 xasprintf (&data, "%s;", data);
667
668 if (critp)
669 xasprintf (&data, "%s%" PRId64 ";", data, crit);
670 else
671 xasprintf (&data, "%s;", data);
672
673 if (minp)
674 xasprintf (&data, "%s%" PRId64 ";", data, minv);
675 else
676 xasprintf (&data, "%s;", data);
677
678 if (maxp)
679 xasprintf (&data, "%s%" PRId64, data, maxv);
584 680
585 return data; 681 return data;
586} 682}
@@ -708,4 +804,3 @@ char *sperfdata_int (const char *label,
708 804
709 return data; 805 return data;
710} 806}
711
diff --git a/plugins/utils.h b/plugins/utils.h
index a436e1c..cb979ce 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -7,7 +7,7 @@
7/* The purpose of this package is to provide safer alternatives to C 7/* The purpose of this package is to provide safer alternatives to C
8functions that might otherwise be vulnerable to hacking. This 8functions that might otherwise be vulnerable to hacking. This
9currently includes a standard suite of validation routines to be sure 9currently includes a standard suite of validation routines to be sure
10that an string argument acually converts to its intended type and a 10that an string argument actually converts to its intended type and a
11suite of string handling routine that do their own memory management 11suite of string handling routine that do their own memory management
12in order to resist overflow attacks. In addition, a few functions are 12in order to resist overflow attacks. In addition, a few functions are
13provided to standardize version and error reporting across the entire 13provided to standardize version and error reporting across the entire
@@ -16,6 +16,7 @@ suite of plugins. */
16/* now some functions etc are being defined in ../lib/utils_base.c */ 16/* now some functions etc are being defined in ../lib/utils_base.c */
17#include "utils_base.h" 17#include "utils_base.h"
18 18
19
19#ifdef NP_EXTRA_OPTS 20#ifdef NP_EXTRA_OPTS
20/* Include extra-opts functions if compiled in */ 21/* Include extra-opts functions if compiled in */
21#include "extra_opts.h" 22#include "extra_opts.h"
@@ -29,13 +30,6 @@ suite of plugins. */
29void support (void); 30void support (void);
30void print_revision (const char *, const char *); 31void print_revision (const char *, const char *);
31 32
32/* Handle timeouts */
33
34extern unsigned int timeout_state;
35extern unsigned int timeout_interval;
36
37RETSIGTYPE timeout_alarm_handler (int);
38
39extern time_t start_time, end_time; 33extern time_t start_time, end_time;
40 34
41/* Test input types */ 35/* Test input types */
@@ -45,6 +39,8 @@ int is_intpos (char *);
45int is_intneg (char *); 39int is_intneg (char *);
46int is_intnonneg (char *); 40int is_intnonneg (char *);
47int is_intpercent (char *); 41int is_intpercent (char *);
42int is_uint64(char *number, uint64_t *target);
43int is_int64(char *number, int64_t *target);
48 44
49int is_numeric (char *); 45int is_numeric (char *);
50int is_positive (char *); 46int is_positive (char *);
@@ -89,14 +85,18 @@ void usage4(const char *) __attribute__((noreturn));
89void usage5(void) __attribute__((noreturn)); 85void usage5(void) __attribute__((noreturn));
90void usage_va(const char *fmt, ...) __attribute__((noreturn)); 86void usage_va(const char *fmt, ...) __attribute__((noreturn));
91 87
92const char *state_text (int);
93
94#define max(a,b) (((a)>(b))?(a):(b)) 88#define max(a,b) (((a)>(b))?(a):(b))
95#define min(a,b) (((a)<(b))?(a):(b)) 89#define min(a,b) (((a)<(b))?(a):(b))
96 90
97char *perfdata (const char *, long int, const char *, int, long int, 91char *perfdata (const char *, long int, const char *, int, long int,
98 int, long int, int, long int, int, long int); 92 int, long int, int, long int, int, long int);
99 93
94char *perfdata_uint64 (const char *, uint64_t , const char *, int, uint64_t,
95 int, uint64_t, int, uint64_t, int, uint64_t);
96
97char *perfdata_int64 (const char *, int64_t, const char *, int, int64_t,
98 int, int64_t, int, int64_t, int, int64_t);
99
100char *fperfdata (const char *, double, const char *, int, double, 100char *fperfdata (const char *, double, const char *, int, double,
101 int, double, int, double, int, double); 101 int, double, int, double, int, double);
102 102