summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/output.c12
-rw-r--r--lib/output.h7
-rw-r--r--plugins/Makefile.am7
-rw-r--r--plugins/check_ssh.c210
-rw-r--r--plugins/check_ssh.d/config.h29
-rw-r--r--plugins/check_swap.c2
-rw-r--r--plugins/netutils.c93
-rw-r--r--plugins/t/check_http.t2
-rw-r--r--plugins/t/check_jabber.t2
-rw-r--r--plugins/t/check_ldap.t2
-rw-r--r--plugins/t/check_ntp.t2
-rw-r--r--plugins/t/check_smtp.t3
-rw-r--r--plugins/t/check_ssh.t114
13 files changed, 341 insertions, 144 deletions
diff --git a/lib/output.c b/lib/output.c
index 17919afc..61fbf832 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -11,6 +11,9 @@
11#include "perfdata.h" 11#include "perfdata.h"
12#include "states.h" 12#include "states.h"
13 13
14// == Global variables
15static mp_output_format output_format = MP_FORMAT_DEFAULT;
16
14// == Prototypes == 17// == Prototypes ==
15static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation); 18static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation);
16static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck); 19static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
@@ -55,7 +58,6 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
55 */ 58 */
56mp_check mp_check_init(void) { 59mp_check mp_check_init(void) {
57 mp_check check = {0}; 60 mp_check check = {0};
58 check.format = MP_FORMAT_DEFAULT;
59 return check; 61 return check;
60} 62}
61 63
@@ -234,7 +236,7 @@ mp_state_enum mp_compute_check_state(const mp_check check) {
234char *mp_fmt_output(mp_check check) { 236char *mp_fmt_output(mp_check check) {
235 char *result = NULL; 237 char *result = NULL;
236 238
237 switch (check.format) { 239 switch (output_format) {
238 case MP_FORMAT_MULTI_LINE: { 240 case MP_FORMAT_MULTI_LINE: {
239 if (check.summary == NULL) { 241 if (check.summary == NULL) {
240 check.summary = get_subcheck_summary(check); 242 check.summary = get_subcheck_summary(check);
@@ -482,7 +484,7 @@ void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
482 */ 484 */
483void mp_exit(mp_check check) { 485void mp_exit(mp_check check) {
484 mp_print_output(check); 486 mp_print_output(check);
485 if (check.format == MP_FORMAT_TEST_JSON) { 487 if (output_format == MP_FORMAT_TEST_JSON) {
486 exit(0); 488 exit(0);
487 } 489 }
488 490
@@ -533,3 +535,7 @@ parsed_output_format mp_parse_output_format(char *format_string) {
533 535
534 return result; 536 return result;
535} 537}
538
539void mp_set_format(mp_output_format format) { output_format = format; }
540
541mp_output_format mp_get_format(void) { return output_format; }
diff --git a/lib/output.h b/lib/output.h
index ffc36f53..2bdfa074 100644
--- a/lib/output.h
+++ b/lib/output.h
@@ -36,13 +36,18 @@ typedef enum output_format {
36#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE 36#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE
37 37
38/* 38/*
39 * Format related functions
40 */
41 void mp_set_format(mp_output_format format);
42 mp_output_format mp_get_format(void);
43
44/*
39 * The main state object of a plugin. Exists only ONCE per plugin. 45 * The main state object of a plugin. Exists only ONCE per plugin.
40 * This is the "root" of a tree of singular checks. 46 * This is the "root" of a tree of singular checks.
41 * The final result is always derived from the children and the "worst" state 47 * The final result is always derived from the children and the "worst" state
42 * in the first layer of subchecks 48 * in the first layer of subchecks
43 */ 49 */
44typedef struct { 50typedef struct {
45 mp_output_format format; // The output format
46 char *summary; // Overall summary, if not set a summary will be automatically generated 51 char *summary; // Overall summary, if not set a summary will be automatically generated
47 mp_subcheck_list *subchecks; 52 mp_subcheck_list *subchecks;
48} mp_check; 53} mp_check;
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index a0e9cabf..28763dfc 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -46,7 +46,12 @@ SUBDIRS = picohttpparser
46 46
47np_test_scripts = tests/test_check_swap.t 47np_test_scripts = tests/test_check_swap.t
48 48
49EXTRA_DIST = t tests $(np_test_scripts) check_swap.d check_dbi.d 49EXTRA_DIST = t \
50 tests \
51 $(np_test_scripts) \
52 check_swap.d \
53 check_dbi.d \
54 check_ssh.d
50 55
51PLUGINHDRS = common.h 56PLUGINHDRS = common.h
52 57
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 42a88cf9..9d0d7cde 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -28,6 +28,9 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "output.h"
32#include "perfdata.h"
33#include "states.h"
31const char *progname = "check_ssh"; 34const char *progname = "check_ssh";
32const char *copyright = "2000-2024"; 35const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
@@ -35,26 +38,26 @@ const char *email = "devel@monitoring-plugins.org";
35#include "./common.h" 38#include "./common.h"
36#include "./netutils.h" 39#include "./netutils.h"
37#include "utils.h" 40#include "utils.h"
41#include "./check_ssh.d/config.h"
38 42
39#ifndef MSG_DONTWAIT 43#ifndef MSG_DONTWAIT
40# define MSG_DONTWAIT 0 44# define MSG_DONTWAIT 0
41#endif 45#endif
42 46
43#define SSH_DFL_PORT 22 47#define BUFF_SZ 256
44#define BUFF_SZ 256
45 48
46static int port = -1;
47static char *server_name = NULL;
48static char *remote_version = NULL;
49static char *remote_protocol = NULL;
50static bool verbose = false; 49static bool verbose = false;
51 50
52static int process_arguments(int /*argc*/, char ** /*argv*/); 51typedef struct process_arguments_wrapper {
53static int validate_arguments(void); 52 int errorcode;
53 check_ssh_config config;
54} process_arguments_wrapper;
55
56static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
54static void print_help(void); 57static void print_help(void);
55void print_usage(void); 58void print_usage(void);
56 59
57static int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol); 60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol);
58 61
59int main(int argc, char **argv) { 62int main(int argc, char **argv) {
60 setlocale(LC_ALL, ""); 63 setlocale(LC_ALL, "");
@@ -64,24 +67,35 @@ int main(int argc, char **argv) {
64 /* Parse extra opts if any */ 67 /* Parse extra opts if any */
65 argv = np_extra_opts(&argc, argv, progname); 68 argv = np_extra_opts(&argc, argv, progname);
66 69
67 if (process_arguments(argc, argv) == ERROR) 70 process_arguments_wrapper tmp_config = process_arguments(argc, argv);
71
72 if (tmp_config.errorcode == ERROR) {
68 usage4(_("Could not parse arguments")); 73 usage4(_("Could not parse arguments"));
74 }
75
76 check_ssh_config config = tmp_config.config;
77
78 mp_check overall = mp_check_init();
79 if (config.output_format_is_set) {
80 mp_set_format(config.output_format);
81 }
69 82
70 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
71 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
72
73 alarm(socket_timeout); 85 alarm(socket_timeout);
74 86
75 /* ssh_connect exits if error is found */ 87 /* ssh_connect exits if error is found */
76 int result = ssh_connect(server_name, port, remote_version, remote_protocol); 88 ssh_connect(&overall, config.server_name, config.port, config.remote_version, config.remote_protocol);
77 89
78 alarm(0); 90 alarm(0);
79 91
80 return (result); 92 mp_exit(overall);
81} 93}
82 94
95#define output_format_index CHAR_MAX + 1
96
83/* process command-line arguments */ 97/* process command-line arguments */
84int process_arguments(int argc, char **argv) { 98process_arguments_wrapper process_arguments(int argc, char **argv) {
85 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 99 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
86 {"version", no_argument, 0, 'V'}, 100 {"version", no_argument, 0, 'V'},
87 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 101 {"host", required_argument, 0, 'H'}, /* backward compatibility */
@@ -93,22 +107,33 @@ int process_arguments(int argc, char **argv) {
93 {"verbose", no_argument, 0, 'v'}, 107 {"verbose", no_argument, 0, 'v'},
94 {"remote-version", required_argument, 0, 'r'}, 108 {"remote-version", required_argument, 0, 'r'},
95 {"remote-protocol", required_argument, 0, 'P'}, 109 {"remote-protocol", required_argument, 0, 'P'},
110 {"output-format", required_argument, 0, output_format_index},
96 {0, 0, 0, 0}}; 111 {0, 0, 0, 0}};
97 112
98 if (argc < 2) 113 process_arguments_wrapper result = {
99 return ERROR; 114 .config = check_ssh_config_init(),
115 .errorcode = OK,
116 };
117
118 if (argc < 2) {
119 result.errorcode = ERROR;
120 return result;
121 }
100 122
101 for (int i = 1; i < argc; i++) 123 for (int i = 1; i < argc; i++) {
102 if (strcmp("-to", argv[i]) == 0) 124 if (strcmp("-to", argv[i]) == 0) {
103 strcpy(argv[i], "-t"); 125 strcpy(argv[i], "-t");
126 }
127 }
104 128
105 int option_char; 129 int option_char;
106 while (true) { 130 while (true) {
107 int option = 0; 131 int option = 0;
108 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option); 132 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
109 133
110 if (option_char == -1 || option_char == EOF) 134 if (option_char == -1 || option_char == EOF) {
111 break; 135 break;
136 }
112 137
113 switch (option_char) { 138 switch (option_char) {
114 case '?': /* help */ 139 case '?': /* help */
@@ -123,10 +148,11 @@ int process_arguments(int argc, char **argv) {
123 verbose = true; 148 verbose = true;
124 break; 149 break;
125 case 't': /* timeout period */ 150 case 't': /* timeout period */
126 if (!is_integer(optarg)) 151 if (!is_intpos(optarg)) {
127 usage2(_("Timeout interval must be a positive integer"), optarg); 152 usage2(_("Timeout interval must be a positive integer"), optarg);
128 else 153 } else {
129 socket_timeout = atoi(optarg); 154 socket_timeout = (unsigned int)atoi(optarg);
155 }
130 break; 156 break;
131 case '4': 157 case '4':
132 address_family = AF_INET; 158 address_family = AF_INET;
@@ -139,50 +165,61 @@ int process_arguments(int argc, char **argv) {
139#endif 165#endif
140 break; 166 break;
141 case 'r': /* remote version */ 167 case 'r': /* remote version */
142 remote_version = optarg; 168 result.config.remote_version = optarg;
143 break; 169 break;
144 case 'P': /* remote version */ 170 case 'P': /* remote version */
145 remote_protocol = optarg; 171 result.config.remote_protocol = optarg;
146 break; 172 break;
147 case 'H': /* host */ 173 case 'H': /* host */
148 if (!is_host(optarg)) 174 if (!is_host(optarg)) {
149 usage2(_("Invalid hostname/address"), optarg); 175 usage2(_("Invalid hostname/address"), optarg);
150 server_name = optarg; 176 }
177 result.config.server_name = optarg;
151 break; 178 break;
152 case 'p': /* port */ 179 case 'p': /* port */
153 if (is_intpos(optarg)) { 180 if (is_intpos(optarg)) {
154 port = atoi(optarg); 181 result.config.port = atoi(optarg);
155 } else { 182 } else {
156 usage2(_("Port number must be a positive integer"), optarg); 183 usage2(_("Port number must be a positive integer"), optarg);
157 } 184 }
185 break;
186 case output_format_index: {
187 parsed_output_format parser = mp_parse_output_format(optarg);
188 if (!parser.parsing_success) {
189 // TODO List all available formats here, maybe add anothoer usage function
190 printf("Invalid output format: %s\n", optarg);
191 exit(STATE_UNKNOWN);
192 }
193
194 result.config.output_format_is_set = true;
195 result.config.output_format = parser.output_format;
196 break;
197 }
158 } 198 }
159 } 199 }
160 200
161 option_char = optind; 201 option_char = optind;
162 if (server_name == NULL && option_char < argc) { 202 if (result.config.server_name == NULL && option_char < argc) {
163 if (is_host(argv[option_char])) { 203 if (is_host(argv[option_char])) {
164 server_name = argv[option_char++]; 204 result.config.server_name = argv[option_char++];
165 } 205 }
166 } 206 }
167 207
168 if (port == -1 && option_char < argc) { 208 if (result.config.port == -1 && option_char < argc) {
169 if (is_intpos(argv[option_char])) { 209 if (is_intpos(argv[option_char])) {
170 port = atoi(argv[option_char++]); 210 result.config.port = atoi(argv[option_char++]);
171 } else { 211 } else {
172 print_usage(); 212 print_usage();
173 exit(STATE_UNKNOWN); 213 exit(STATE_UNKNOWN);
174 } 214 }
175 } 215 }
176 216
177 return validate_arguments(); 217 if (result.config.server_name == NULL) {
178} 218 result.errorcode = ERROR;
219 return result;
220 }
179 221
180int validate_arguments(void) { 222 return result;
181 if (server_name == NULL)
182 return ERROR;
183 if (port == -1) /* funky, but allows -p to override stray integer in args */
184 port = SSH_DFL_PORT;
185 return OK;
186} 223}
187 224
188/************************************************************************ 225/************************************************************************
@@ -191,28 +228,34 @@ int validate_arguments(void) {
191 * 228 *
192 *-----------------------------------------------------------------------*/ 229 *-----------------------------------------------------------------------*/
193 230
194int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol) { 231int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) {
195 struct timeval tv; 232 struct timeval tv;
196 gettimeofday(&tv, NULL); 233 gettimeofday(&tv, NULL);
197 234
198 int socket; 235 int socket;
199 int result = my_tcp_connect(haddr, hport, &socket); 236 int result = my_tcp_connect(haddr, hport, &socket);
200 237
201 if (result != STATE_OK) 238 mp_subcheck connection_sc = mp_subcheck_init();
239 if (result != STATE_OK) {
240 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
241 xasprintf(&connection_sc.output, "Failed to establish TCP connection to Host %s and Port %d", haddr, hport);
242 mp_add_subcheck_to_check(overall, connection_sc);
202 return result; 243 return result;
244 }
203 245
204 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char)); 246 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
205 char *buffer = NULL; 247 char *buffer = NULL;
206 ssize_t recv_ret = 0; 248 size_t recv_ret = 0;
207 char *version_control_string = NULL; 249 char *version_control_string = NULL;
208 ssize_t byte_offset = 0; 250 size_t byte_offset = 0;
209 while ((version_control_string == NULL) && (recv_ret = recv(socket, output + byte_offset, BUFF_SZ - byte_offset, 0) > 0)) { 251 while ((version_control_string == NULL) &&
252 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset), 0) > 0)) {
210 253
211 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 254 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
212 byte_offset = 0; 255 byte_offset = 0;
213 256
214 char *index = NULL; 257 char *index = NULL;
215 int len = 0; 258 unsigned long len = 0;
216 while ((index = strchr(output + byte_offset, '\n')) != NULL) { 259 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
217 /*Partition the buffer so that this line is a separate string, 260 /*Partition the buffer so that this line is a separate string,
218 * by replacing the newline with NUL*/ 261 * by replacing the newline with NUL*/
@@ -243,14 +286,23 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
243 } 286 }
244 287
245 if (recv_ret < 0) { 288 if (recv_ret < 0) {
246 printf("SSH CRITICAL - %s", strerror(errno)); 289 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
247 exit(STATE_CRITICAL); 290 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - %s", strerror(errno));
291 mp_add_subcheck_to_check(overall, connection_sc);
292 return OK;
248 } 293 }
249 294
250 if (version_control_string == NULL) { 295 if (version_control_string == NULL) {
251 printf("SSH CRITICAL - No version control string received"); 296 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
252 exit(STATE_CRITICAL); 297 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - No version control string received");
298 mp_add_subcheck_to_check(overall, connection_sc);
299 return OK;
253 } 300 }
301
302 connection_sc = mp_set_subcheck_state(connection_sc, STATE_OK);
303 xasprintf(&connection_sc.output, "%s", "Initial connection succeeded");
304 mp_add_subcheck_to_check(overall, connection_sc);
305
254 /* 306 /*
255 * "When the connection has been established, both sides MUST send an 307 * "When the connection has been established, both sides MUST send an
256 * identification string. This identification string MUST be 308 * identification string. This identification string MUST be
@@ -259,8 +311,9 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
259 * - RFC 4253:4.2 311 * - RFC 4253:4.2
260 */ 312 */
261 strip(version_control_string); 313 strip(version_control_string);
262 if (verbose) 314 if (verbose) {
263 printf("%s\n", version_control_string); 315 printf("%s\n", version_control_string);
316 }
264 317
265 char *ssh_proto = version_control_string + 4; 318 char *ssh_proto = version_control_string + 4;
266 319
@@ -288,41 +341,65 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
288 if (tmp) { 341 if (tmp) {
289 ssh_server[tmp - ssh_server] = '\0'; 342 ssh_server[tmp - ssh_server] = '\0';
290 } 343 }
344
345 mp_subcheck protocol_validity_sc = mp_subcheck_init();
291 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 346 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
292 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string); 347 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
293 exit(STATE_CRITICAL); 348 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s", version_control_string);
349 mp_add_subcheck_to_check(overall, protocol_validity_sc);
350 return OK;
294 } 351 }
352
353 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
354 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string);
355 mp_add_subcheck_to_check(overall, protocol_validity_sc);
356
295 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0; 357 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
296 358
297 static char *rev_no = VERSION; 359 static char *rev_no = VERSION;
298 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no); 360 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
299 send(socket, buffer, strlen(buffer), MSG_DONTWAIT); 361 send(socket, buffer, strlen(buffer), MSG_DONTWAIT);
300 if (verbose) 362 if (verbose) {
301 printf("%s\n", buffer); 363 printf("%s\n", buffer);
364 }
302 365
303 if (remote_version && strcmp(remote_version, ssh_server)) { 366 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
304 printf(_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), ssh_server, ssh_proto, remote_version); 367 mp_subcheck remote_version_sc = mp_subcheck_init();
368 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
369 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto,
370 desired_remote_version);
305 close(socket); 371 close(socket);
306 exit(STATE_CRITICAL); 372 mp_add_subcheck_to_check(overall, remote_version_sc);
373 return OK;
307 } 374 }
308 375
309 double elapsed_time = (double)deltime(tv) / 1.0e6; 376 double elapsed_time = (double)deltime(tv) / 1.0e6;
310 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 377 mp_perfdata time_pd = perfdata_init();
311 printf(_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), ssh_server, ssh_proto, remote_protocol, 378 time_pd.value = mp_create_pd_value(elapsed_time);
312 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout)); 379 time_pd.label = "time";
313 close(socket); 380 time_pd.max_present = true;
314 exit(STATE_CRITICAL); 381 time_pd.max = mp_create_pd_value(socket_timeout);
382
383 mp_subcheck protocol_version_sc = mp_subcheck_init();
384 mp_add_perfdata_to_subcheck(&protocol_version_sc, time_pd);
385
386 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
387 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL);
388 xasprintf(&protocol_version_sc.output, _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server, ssh_proto,
389 desired_remote_protocol);
390 } else {
391 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK);
392 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)", ssh_server, ssh_proto);
315 } 393 }
316 394
317 printf(_("SSH OK - %s (protocol %s) | %s\n"), ssh_server, ssh_proto, 395 mp_add_subcheck_to_check(overall, protocol_version_sc);
318 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout));
319 close(socket); 396 close(socket);
320 exit(STATE_OK); 397 return OK;
321} 398}
322 399
323void print_help(void) { 400void print_help(void) {
324 char *myport; 401 char *myport;
325 xasprintf(&myport, "%d", SSH_DFL_PORT); 402 xasprintf(&myport, "%d", default_ssh_port);
326 403
327 print_revision(progname, NP_VERSION); 404 print_revision(progname, NP_VERSION);
328 405
@@ -349,6 +426,7 @@ void print_help(void) {
349 426
350 printf(" %s\n", "-P, --remote-protocol=STRING"); 427 printf(" %s\n", "-P, --remote-protocol=STRING");
351 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 428 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
429 printf(UT_OUTPUT_FORMAT);
352 430
353 printf(UT_VERBOSE); 431 printf(UT_VERBOSE);
354 432
@@ -357,5 +435,5 @@ void print_help(void) {
357 435
358void print_usage(void) { 436void print_usage(void) {
359 printf("%s\n", _("Usage:")); 437 printf("%s\n", _("Usage:"));
360 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname); 438 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname);
361} 439}
diff --git a/plugins/check_ssh.d/config.h b/plugins/check_ssh.d/config.h
new file mode 100644
index 00000000..c150fd30
--- /dev/null
+++ b/plugins/check_ssh.d/config.h
@@ -0,0 +1,29 @@
1#pragma once
2
3#include <stddef.h>
4#include "../../lib/monitoringplug.h"
5
6const int default_ssh_port = 22;
7
8typedef struct check_ssh_config {
9 int port;
10 char *server_name;
11 char *remote_version;
12 char *remote_protocol;
13
14 bool output_format_is_set;
15 mp_output_format output_format;
16} check_ssh_config;
17
18check_ssh_config check_ssh_config_init(void) {
19 check_ssh_config tmp = {
20 .port = default_ssh_port,
21 .server_name = NULL,
22 .remote_version = NULL,
23 .remote_protocol = NULL,
24
25 .output_format_is_set = false,
26 };
27
28 return tmp;
29}
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index 4d3b6099..cb95949a 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -93,7 +93,7 @@ int main(int argc, char **argv) {
93 double percent_used; 93 double percent_used;
94 mp_check overall = mp_check_init(); 94 mp_check overall = mp_check_init();
95 if (config.output_format_is_set) { 95 if (config.output_format_is_set) {
96 overall.format = config.output_format; 96 mp_set_format(config.output_format);
97 } 97 }
98 mp_subcheck sc1 = mp_subcheck_init(); 98 mp_subcheck sc1 = mp_subcheck_init();
99 sc1 = mp_set_subcheck_default_state(sc1, STATE_OK); 99 sc1 = mp_set_subcheck_default_state(sc1, STATE_OK);
diff --git a/plugins/netutils.c b/plugins/netutils.c
index ee81912a..e2916c65 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -28,6 +28,8 @@
28 *****************************************************************************/ 28 *****************************************************************************/
29 29
30#include "common.h" 30#include "common.h"
31#include "output.h"
32#include "states.h"
31#include "netutils.h" 33#include "netutils.h"
32 34
33unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT; 35unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
@@ -43,12 +45,19 @@ int address_family = AF_INET;
43 45
44/* handles socket timeouts */ 46/* handles socket timeouts */
45void socket_timeout_alarm_handler(int sig) { 47void socket_timeout_alarm_handler(int sig) {
46 if (sig == SIGALRM) 48 mp_subcheck timeout_sc = mp_subcheck_init();
47 printf(_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 49 timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
48 else
49 printf(_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout);
50 50
51 exit(socket_timeout_state); 51 if (sig == SIGALRM) {
52 xasprintf(&timeout_sc.output, _("Socket timeout after %d seconds\n"), socket_timeout);
53 } else {
54 xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
55 }
56
57 mp_check overall = mp_check_init();
58 mp_add_subcheck_to_check(&overall, timeout_sc);
59
60 mp_exit(overall);
52} 61}
53 62
54/* connects to a host on a specified tcp port, sends a string, and gets a 63/* connects to a host on a specified tcp port, sends a string, and gets a
@@ -65,12 +74,13 @@ int process_tcp_request2(const char *server_address, int server_port, const char
65 int recv_length = 0; 74 int recv_length = 0;
66 75
67 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP); 76 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP);
68 if (result != STATE_OK) 77 if (result != STATE_OK) {
69 return STATE_CRITICAL; 78 return STATE_CRITICAL;
79 }
70 80
71 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 81 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
72 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 82 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
73 printf("%s\n", _("Send failed")); 83 // printf("%s\n", _("Send failed"));
74 result = STATE_WARNING; 84 result = STATE_WARNING;
75 } 85 }
76 86
@@ -87,7 +97,7 @@ int process_tcp_request2(const char *server_address, int server_port, const char
87 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */ 97 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */
88 if (!recv_length) { 98 if (!recv_length) {
89 strcpy(recv_buffer, ""); 99 strcpy(recv_buffer, "");
90 printf("%s\n", _("No data was received from host!")); 100 // printf("%s\n", _("No data was received from host!"));
91 result = STATE_WARNING; 101 result = STATE_WARNING;
92 } else { /* this one failed, but previous ones worked */ 102 } else { /* this one failed, but previous ones worked */
93 recv_buffer[recv_length] = 0; 103 recv_buffer[recv_length] = 0;
@@ -130,8 +140,9 @@ int process_request(const char *server_address, int server_port, int proto, cons
130 result = STATE_OK; 140 result = STATE_OK;
131 141
132 result = np_net_connect(server_address, server_port, &sd, proto); 142 result = np_net_connect(server_address, server_port, &sd, proto);
133 if (result != STATE_OK) 143 if (result != STATE_OK) {
134 return STATE_CRITICAL; 144 return STATE_CRITICAL;
145 }
135 146
136 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size); 147 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size);
137 148
@@ -169,15 +180,16 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
169 host_name++; 180 host_name++;
170 len -= 2; 181 len -= 2;
171 } 182 }
172 if (len >= sizeof(host)) 183 if (len >= sizeof(host)) {
173 return STATE_UNKNOWN; 184 return STATE_UNKNOWN;
185 }
174 memcpy(host, host_name, len); 186 memcpy(host, host_name, len);
175 host[len] = '\0'; 187 host[len] = '\0';
176 snprintf(port_str, sizeof(port_str), "%d", port); 188 snprintf(port_str, sizeof(port_str), "%d", port);
177 result = getaddrinfo(host, port_str, &hints, &res); 189 result = getaddrinfo(host, port_str, &hints, &res);
178 190
179 if (result != 0) { 191 if (result != 0) {
180 printf("%s\n", gai_strerror(result)); 192 // printf("%s\n", gai_strerror(result));
181 return STATE_UNKNOWN; 193 return STATE_UNKNOWN;
182 } 194 }
183 195
@@ -187,7 +199,7 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
187 *sd = socket(r->ai_family, socktype, r->ai_protocol); 199 *sd = socket(r->ai_family, socktype, r->ai_protocol);
188 200
189 if (*sd < 0) { 201 if (*sd < 0) {
190 printf("%s\n", _("Socket creation failed")); 202 // printf("%s\n", _("Socket creation failed"));
191 freeaddrinfo(r); 203 freeaddrinfo(r);
192 return STATE_UNKNOWN; 204 return STATE_UNKNOWN;
193 } 205 }
@@ -226,21 +238,23 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
226 die(STATE_UNKNOWN, _("Socket creation failed")); 238 die(STATE_UNKNOWN, _("Socket creation failed"));
227 } 239 }
228 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 240 result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
229 if (result < 0 && errno == ECONNREFUSED) 241 if (result < 0 && errno == ECONNREFUSED) {
230 was_refused = true; 242 was_refused = true;
243 }
231 } 244 }
232 245
233 if (result == 0) 246 if (result == 0) {
234 return STATE_OK; 247 return STATE_OK;
235 else if (was_refused) { 248 } else if (was_refused) {
236 switch (econn_refuse_state) { /* a user-defined expected outcome */ 249 switch (econn_refuse_state) { /* a user-defined expected outcome */
237 case STATE_OK: 250 case STATE_OK:
238 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 251 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
239 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */ 252 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
240 if (is_socket) 253 if (is_socket) {
241 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 254 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
242 else 255 } else {
243 printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno)); 256 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
257 }
244 return STATE_CRITICAL; 258 return STATE_CRITICAL;
245 break; 259 break;
246 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */ 260 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
@@ -248,10 +262,11 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
248 break; 262 break;
249 } 263 }
250 } else { 264 } else {
251 if (is_socket) 265 if (is_socket) {
252 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 266 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
253 else 267 } else {
254 printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno)); 268 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
269 }
255 return STATE_CRITICAL; 270 return STATE_CRITICAL;
256 } 271 }
257} 272}
@@ -265,7 +280,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
265 280
266 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 281 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
267 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 282 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
268 printf("%s\n", _("Send failed")); 283 // printf("%s\n", _("Send failed"));
269 result = STATE_WARNING; 284 result = STATE_WARNING;
270 } 285 }
271 286
@@ -280,7 +295,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
280 /* make sure some data has arrived */ 295 /* make sure some data has arrived */
281 if (!FD_ISSET(sd, &readfds)) { 296 if (!FD_ISSET(sd, &readfds)) {
282 strcpy(recv_buffer, ""); 297 strcpy(recv_buffer, "");
283 printf("%s\n", _("No data was received from host!")); 298 // printf("%s\n", _("No data was received from host!"));
284 result = STATE_WARNING; 299 result = STATE_WARNING;
285 } 300 }
286 301
@@ -288,11 +303,13 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
288 recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0); 303 recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0);
289 if (recv_result == -1) { 304 if (recv_result == -1) {
290 strcpy(recv_buffer, ""); 305 strcpy(recv_buffer, "");
291 if (proto != IPPROTO_TCP) 306 if (proto != IPPROTO_TCP) {
292 printf("%s\n", _("Receive failed")); 307 // printf("%s\n", _("Receive failed"));
308 }
293 result = STATE_WARNING; 309 result = STATE_WARNING;
294 } else 310 } else {
295 recv_buffer[recv_result] = 0; 311 recv_buffer[recv_result] = 0;
312 }
296 313
297 /* die returned string */ 314 /* die returned string */
298 recv_buffer[recv_size - 1] = 0; 315 recv_buffer[recv_size - 1] = 0;
@@ -301,26 +318,30 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
301} 318}
302 319
303bool is_host(const char *address) { 320bool is_host(const char *address) {
304 if (is_addr(address) || is_hostname(address)) 321 if (is_addr(address) || is_hostname(address)) {
305 return (true); 322 return (true);
323 }
306 324
307 return (false); 325 return (false);
308} 326}
309 327
310void host_or_die(const char *str) { 328void host_or_die(const char *str) {
311 if (!str || (!is_addr(str) && !is_hostname(str))) 329 if (!str || (!is_addr(str) && !is_hostname(str))) {
312 usage_va(_("Invalid hostname/address - %s"), str); 330 usage_va(_("Invalid hostname/address - %s"), str);
331 }
313} 332}
314 333
315bool is_addr(const char *address) { 334bool is_addr(const char *address) {
316#ifdef USE_IPV6 335#ifdef USE_IPV6
317 if (address_family == AF_INET && is_inet_addr(address)) 336 if (address_family == AF_INET && is_inet_addr(address)) {
318 return true; 337 return true;
319 else if (address_family == AF_INET6 && is_inet6_addr(address)) 338 } else if (address_family == AF_INET6 && is_inet6_addr(address)) {
320 return true; 339 return true;
340 }
321#else 341#else
322 if (is_inet_addr(address)) 342 if (is_inet_addr(address)) {
323 return (true); 343 return (true);
344 }
324#endif 345#endif
325 346
326 return (false); 347 return (false);
@@ -335,11 +356,13 @@ int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) {
335 hints.ai_family = family; 356 hints.ai_family = family;
336 357
337 retval = getaddrinfo(in, NULL, &hints, &res); 358 retval = getaddrinfo(in, NULL, &hints, &res);
338 if (retval != 0) 359 if (retval != 0) {
339 return false; 360 return false;
361 }
340 362
341 if (ss != NULL) 363 if (ss != NULL) {
342 memcpy(ss, res->ai_addr, res->ai_addrlen); 364 memcpy(ss, res->ai_addr, res->ai_addrlen);
365 }
343 freeaddrinfo(res); 366 freeaddrinfo(res);
344 return true; 367 return true;
345} 368}
diff --git a/plugins/t/check_http.t b/plugins/t/check_http.t
index 6ab4a5b6..bb1fd27d 100644
--- a/plugins/t/check_http.t
+++ b/plugins/t/check_http.t
@@ -45,7 +45,7 @@ $res = NPTest->testCmd(
45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3" 45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
46 ); 46 );
47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); 47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
48cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK"); 48like( $res->output, "/Socket timeout after/", "Output OK");
49 49
50$res = NPTest->testCmd( 50$res = NPTest->testCmd(
51 "./$plugin $hostname_invalid -wt 1 -ct 2" 51 "./$plugin $hostname_invalid -wt 1 -ct 2"
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index fcdae179..08cadcbd 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -17,7 +17,7 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (no
17 17
18my $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/';
19 19
20my $jabberUnresponsive = '/CRITICAL\s-\sSocket timeout after\s\d+\sseconds/'; 20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
21 21
22my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/'; 22my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/';
23 23
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t
index b8a4a766..fcba0393 100644
--- a/plugins/t/check_ldap.t
+++ b/plugins/t/check_ldap.t
@@ -24,7 +24,7 @@ SKIP: {
24 24
25 $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1"); 25 $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1");
26 is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" ); 26 is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" );
27 is( $result->output, 'CRITICAL - Socket timeout after 2 seconds', "output ok" ); 27 like($result->output, '/Socket timeout after \d+ seconds/', "output ok" );
28}; 28};
29 29
30SKIP: { 30SKIP: {
diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t
index b8fc8fdf..a8ac7bb8 100644
--- a/plugins/t/check_ntp.t
+++ b/plugins/t/check_ntp.t
@@ -37,7 +37,7 @@ my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?
37my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/'; 37my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
38my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/'; 38my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/';
39my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/'; 39my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
40my $ntp_noresponse = '/^(CRITICAL - Socket timeout after 3 seconds)|(NTP CRITICAL: No response from NTP server)$/'; 40my $ntp_noresponse = '/(.*Socket timeout after \d+ seconds.*)|(.*No response from NTP server.*)/';
41my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/'; 41my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/';
42 42
43 43
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t
index 1a1ebe3e..73b4a1fd 100644
--- a/plugins/t/check_smtp.t
+++ b/plugins/t/check_smtp.t
@@ -24,7 +24,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
24 "An invalid (not known to DNS) hostname", "nosuchhost" ); 24 "An invalid (not known to DNS) hostname", "nosuchhost" );
25my $res; 25my $res;
26 26
27plan tests => 16; 27plan tests => 15;
28 28
29SKIP: { 29SKIP: {
30 skip "No SMTP server defined", 4 unless $host_tcp_smtp; 30 skip "No SMTP server defined", 4 unless $host_tcp_smtp;
@@ -73,7 +73,6 @@ SKIP: {
73 my $unused_port = 4465; 73 my $unused_port = 4465;
74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); 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" ); 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} 76}
78 77
79$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" ); 78$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" );
diff --git a/plugins/t/check_ssh.t b/plugins/t/check_ssh.t
index 907d33a8..8a20782e 100644
--- a/plugins/t/check_ssh.t
+++ b/plugins/t/check_ssh.t
@@ -5,10 +5,10 @@
5# 5#
6 6
7use strict; 7use strict;
8use warnings;
8use Test::More; 9use Test::More;
9use NPTest; 10use NPTest;
10 11use JSON;
11my $res;
12 12
13# Required parameters 13# Required parameters
14my $ssh_host = getTestParameter("NP_SSH_HOST", 14my $ssh_host = getTestParameter("NP_SSH_HOST",
@@ -23,30 +23,38 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID",
23 "An invalid (not known to DNS) hostname", 23 "An invalid (not known to DNS) hostname",
24 "nosuchhost" ); 24 "nosuchhost" );
25 25
26 my $outputFormat = '--output-format mp-test-json';
27
28plan tests => 24;
26 29
27plan tests => 14 + 6; 30my $output;
31my $result;
28 32
29SKIP: { 33SKIP: {
30 skip "SSH_HOST must be defined", 6 unless $ssh_host; 34 skip "SSH_HOST must be defined", 6 unless $ssh_host;
35
36
31 my $result = NPTest->testCmd( 37 my $result = NPTest->testCmd(
32 "./check_ssh -H $ssh_host" 38 "./check_ssh -H $ssh_host" ." ". $outputFormat
33 ); 39 );
34 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); 40 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
35 like($result->output, '/^SSH OK - /', "Status text if command returned none (OK)"); 41 $output = decode_json($result->output);
42 is($output->{'state'}, "OK", "State was correct");
36 43
37 44
38 $result = NPTest->testCmd( 45 $result = NPTest->testCmd(
39 "./check_ssh -H $host_nonresponsive -t 2" 46 "./check_ssh -H $host_nonresponsive -t 2" ." ". $outputFormat
40 ); 47 );
41 cmp_ok($result->return_code, '==', 2, "Exit with return code 0 (OK)"); 48 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
42 like($result->output, '/^CRITICAL - Socket timeout after 2 seconds/', "Status text if command returned none (OK)"); 49 $output = decode_json($result->output);
50 is($output->{'state'}, "CRITICAL", "State was correct");
43 51
44 52
45 53
46 $result = NPTest->testCmd( 54 $result = NPTest->testCmd(
47 "./check_ssh -H $hostname_invalid -t 2" 55 "./check_ssh -H $hostname_invalid -t 2" ." ". $outputFormat
48 ); 56 );
49 cmp_ok($result->return_code, '==', 3, "Exit with return code 0 (OK)"); 57 cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)");
50 like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)"); 58 like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)");
51 59
52 60
@@ -63,46 +71,80 @@ SKIP: {
63 # 71 #
64 # where `comments` is optional, protoversion is the SSH protocol version and 72 # where `comments` is optional, protoversion is the SSH protocol version and
65 # softwareversion is an arbitrary string representing the server software version 73 # softwareversion is an arbitrary string representing the server software version
74
75 my $found_version = 0;
76
66 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|"); 77 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|");
67 sleep 0.1; 78 sleep 0.1;
68 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 79 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
69 cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string"); 80 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
70 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK"); 81 $output = decode_json($result->output);
82 is($output->{'state'}, "OK", "State was correct");
83
84 # looking for the version
85 for my $subcheck (@{$output->{'checks'}}) {
86 if ($subcheck->{'output'} =~ /.*nagiosplug.ssh.0.1 \(protocol version: 2.0\).*/ ){
87 $found_version = 1;
88 }
89 }
90 cmp_ok($found_version, '==', 1, "Output OK");
71 close NC; 91 close NC;
72 92
73 open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|"); 93 open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|");
74 sleep 0.1; 94 sleep 0.1;
75 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 95 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
76 cmp_ok( $res->return_code, "==", 0, "Got SSH protocol version control string with non-alpha softwareversion string"); 96 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
77 like( $res->output, '/^SSH OK - 3.2.9.1 \(protocol 2.0\)/', "Output OK for non-alpha softwareversion string"); 97 $output = decode_json($result->output);
98 is($output->{'state'}, "OK", "State was correct");
99
100 $found_version = 0;
101 for my $subcheck (@{$output->{'checks'}}) {
102 if ($subcheck->{'output'} =~ /3.2.9.1 \(protocol version: 2.0\)/ ){
103 $found_version = 1;
104 }
105 }
106 cmp_ok($found_version, '==', 1, "Output OK");
78 close NC; 107 close NC;
79 108
80 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |"); 109 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |");
81 sleep 0.1; 110 sleep 0.1;
82 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ); 111 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ." ". $outputFormat);
83 cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string, and parsed comment appropriately"); 112 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
84 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK"); 113 $output = decode_json($result->output);
114 is($output->{'state'}, "OK", "State was correct");
115
116 # looking for the version
117 $found_version = 0;
118 for my $subcheck (@{$output->{'checks'}}) {
119 if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.1 \(protocol version: 2.0\)/ ){
120 $found_version = 1;
121 }
122 }
123 cmp_ok($found_version, '==', 1, "Output OK");
85 close NC; 124 close NC;
86 125
87 open(NC, "echo 'SSH-' | nc ${nc_flags}|"); 126 open(NC, "echo 'SSH-' | nc ${nc_flags}|");
88 sleep 0.1; 127 sleep 0.1;
89 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 128 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
90 cmp_ok( $res->return_code, '==', 2, "Got invalid SSH protocol version control string"); 129 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
91 like( $res->output, '/^SSH CRITICAL/', "Output OK"); 130 $output = decode_json($result->output);
131 is($output->{'state'}, "CRITICAL", "Got invalid SSH protocol version control string");
92 close NC; 132 close NC;
93 133
94 open(NC, "echo '' | nc ${nc_flags}|"); 134 open(NC, "echo '' | nc ${nc_flags}|");
95 sleep 0.1; 135 sleep 0.1;
96 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 136 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
97 cmp_ok( $res->return_code, '==', 2, "No version control string received"); 137 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
98 like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK"); 138 $output = decode_json($result->output);
139 is($output->{'state'}, "CRITICAL", "No version control string received");
99 close NC; 140 close NC;
100 141
101 open(NC, "echo 'Not a version control string' | nc ${nc_flags}|"); 142 open(NC, "echo 'Not a version control string' | nc ${nc_flags}|");
102 sleep 0.1; 143 sleep 0.1;
103 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 144 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
104 cmp_ok( $res->return_code, '==', 2, "No version control string received"); 145 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
105 like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK"); 146 $output = decode_json($result->output);
147 is($output->{'state'}, "CRITICAL", "No version control string received");
106 close NC; 148 close NC;
107 149
108 150
@@ -116,8 +158,18 @@ SKIP: {
116 echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2; 158 echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2;
117 echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|"); 159 echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|");
118 sleep 0.1; 160 sleep 0.1;
119 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 161 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
120 cmp_ok( $res->return_code, '==', 0, "Got delayed SSH protocol version control string"); 162 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
121 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.2 \(protocol 2.0\)/', "Output OK"); 163 $output = decode_json($result->output);
164 is($output->{'state'}, "OK", "State was correct");
165
166 # looking for the version
167 $found_version = 0;
168 for my $subcheck (@{$output->{'checks'}}) {
169 if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.2 \(protocol version: 2.0\)/ ){
170 $found_version = 1;
171 }
172 }
173 cmp_ok($found_version, '==', 1, "Output OK");
122 close NC; 174 close NC;
123} 175}