summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-08-01 14:44:44 +0200
committerGitHub <noreply@github.com>2025-08-01 14:44:44 +0200
commit1dfb5a0c10881b43cb60cf93bab63648c61201b5 (patch)
treebe1c2efe8dead0438d2f2ae39af3197e806434d0
parentb05087d9aac2369b2ce19e45441da5b761b36a42 (diff)
parent2757550558d509aa5c95d8834ee76d803e110161 (diff)
downloadmonitoring-plugins-1dfb5a0c.tar.gz
Merge pull request #2138 from RincewindsHat/improvements/check_ssh
Improvements/check ssh
-rw-r--r--plugins/check_ssh.c81
1 files changed, 47 insertions, 34 deletions
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 2c76fa84..f6c8d551 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -57,7 +57,8 @@ static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*
57static void print_help(void); 57static void print_help(void);
58void print_usage(void); 58void print_usage(void);
59 59
60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol); 60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version,
61 char *remote_protocol);
61 62
62int main(int argc, char **argv) { 63int main(int argc, char **argv) {
63 setlocale(LC_ALL, ""); 64 setlocale(LC_ALL, "");
@@ -85,7 +86,8 @@ int main(int argc, char **argv) {
85 alarm(socket_timeout); 86 alarm(socket_timeout);
86 87
87 /* ssh_connect exits if error is found */ 88 /* ssh_connect exits if error is found */
88 ssh_connect(&overall, config.server_name, config.port, config.remote_version, config.remote_protocol); 89 ssh_connect(&overall, config.server_name, config.port, config.remote_version,
90 config.remote_protocol);
89 91
90 alarm(0); 92 alarm(0);
91 93
@@ -96,19 +98,20 @@ int main(int argc, char **argv) {
96 98
97/* process command-line arguments */ 99/* process command-line arguments */
98process_arguments_wrapper process_arguments(int argc, char **argv) { 100process_arguments_wrapper process_arguments(int argc, char **argv) {
99 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 101 static struct option longopts[] = {
100 {"version", no_argument, 0, 'V'}, 102 {"help", no_argument, 0, 'h'},
101 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 103 {"version", no_argument, 0, 'V'},
102 {"hostname", required_argument, 0, 'H'}, 104 {"host", required_argument, 0, 'H'}, /* backward compatibility */
103 {"port", required_argument, 0, 'p'}, 105 {"hostname", required_argument, 0, 'H'},
104 {"use-ipv4", no_argument, 0, '4'}, 106 {"port", required_argument, 0, 'p'},
105 {"use-ipv6", no_argument, 0, '6'}, 107 {"use-ipv4", no_argument, 0, '4'},
106 {"timeout", required_argument, 0, 't'}, 108 {"use-ipv6", no_argument, 0, '6'},
107 {"verbose", no_argument, 0, 'v'}, 109 {"timeout", required_argument, 0, 't'},
108 {"remote-version", required_argument, 0, 'r'}, 110 {"verbose", no_argument, 0, 'v'},
109 {"remote-protocol", required_argument, 0, 'P'}, 111 {"remote-version", required_argument, 0, 'r'},
110 {"output-format", required_argument, 0, output_format_index}, 112 {"remote-protocol", required_argument, 0, 'P'},
111 {0, 0, 0, 0}}; 113 {"output-format", required_argument, 0, output_format_index},
114 {0, 0, 0, 0}};
112 115
113 process_arguments_wrapper result = { 116 process_arguments_wrapper result = {
114 .config = check_ssh_config_init(), 117 .config = check_ssh_config_init(),
@@ -228,7 +231,8 @@ process_arguments_wrapper process_arguments(int argc, char **argv) {
228 * 231 *
229 *-----------------------------------------------------------------------*/ 232 *-----------------------------------------------------------------------*/
230 233
231int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) { 234int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version,
235 char *desired_remote_protocol) {
232 struct timeval tv; 236 struct timeval tv;
233 gettimeofday(&tv, NULL); 237 gettimeofday(&tv, NULL);
234 238
@@ -238,32 +242,34 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
238 mp_subcheck connection_sc = mp_subcheck_init(); 242 mp_subcheck connection_sc = mp_subcheck_init();
239 if (result != STATE_OK) { 243 if (result != STATE_OK) {
240 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL); 244 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); 245 xasprintf(&connection_sc.output,
246 "Failed to establish TCP connection to Host %s and Port %d", haddr, hport);
242 mp_add_subcheck_to_check(overall, connection_sc); 247 mp_add_subcheck_to_check(overall, connection_sc);
243 return result; 248 return result;
244 } 249 }
245 250
246 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char)); 251 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
247 char *buffer = NULL; 252 char *buffer = NULL;
248 size_t recv_ret = 0; 253 ssize_t recv_ret = 0;
249 char *version_control_string = NULL; 254 char *version_control_string = NULL;
250 size_t byte_offset = 0; 255 size_t byte_offset = 0;
251 while ((version_control_string == NULL) && 256 while ((version_control_string == NULL) &&
252 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset), 0) > 0)) { 257 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset),
258 0) > 0)) {
253 259
254 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 260 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
255 byte_offset = 0; 261 byte_offset = 0;
256 262
257 char *index = NULL; 263 char *index = NULL;
258 size_t len = 0;
259 while ((index = strchr(output + byte_offset, '\n')) != NULL) { 264 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
260 /*Partition the buffer so that this line is a separate string, 265 /*Partition the buffer so that this line is a separate string,
261 * by replacing the newline with NUL*/ 266 * by replacing the newline with NUL*/
262 output[(index - output)] = '\0'; 267 output[(index - output)] = '\0';
263 len = strlen(output + byte_offset); 268 size_t len = strlen(output + byte_offset);
264 269
265 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) { 270 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) {
266 /*if the string starts with SSH-, this _should_ be a valid version control string*/ 271 /*if the string starts with SSH-, this _should_ be a valid version control
272 * string*/
267 version_control_string = output + byte_offset; 273 version_control_string = output + byte_offset;
268 break; 274 break;
269 } 275 }
@@ -283,13 +289,13 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
283 memset(output + byte_offset, 0, BUFF_SZ - byte_offset); 289 memset(output + byte_offset, 0, BUFF_SZ - byte_offset);
284 } 290 }
285 } else { 291 } else {
286 byte_offset += recv_ret; 292 byte_offset += (size_t)recv_ret;
287 } 293 }
288 } 294 }
289 295
290 if (recv_ret < 0) { 296 if (recv_ret < 0) {
291 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL); 297 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
292 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - %s", strerror(errno)); 298 xasprintf(&connection_sc.output, "%s - %s", "SSH CRITICAL - ", strerror(errno));
293 mp_add_subcheck_to_check(overall, connection_sc); 299 mp_add_subcheck_to_check(overall, connection_sc);
294 return OK; 300 return OK;
295 } 301 }
@@ -335,7 +341,8 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
335 * "1.x" (e.g., "1.5" or "1.3")." 341 * "1.x" (e.g., "1.5" or "1.3")."
336 * - RFC 4253:5 342 * - RFC 4253:5
337 */ 343 */
338 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */ 344 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") +
345 1; /* (+1 for the '-' separating protoversion from softwareversion) */
339 346
340 /* If there's a space in the version string, whatever's after the space is a comment 347 /* If there's a space in the version string, whatever's after the space is a comment
341 * (which is NOT part of the server name/version)*/ 348 * (which is NOT part of the server name/version)*/
@@ -347,13 +354,15 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
347 mp_subcheck protocol_validity_sc = mp_subcheck_init(); 354 mp_subcheck protocol_validity_sc = mp_subcheck_init();
348 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 355 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
349 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL); 356 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
350 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s", version_control_string); 357 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s",
358 version_control_string);
351 mp_add_subcheck_to_check(overall, protocol_validity_sc); 359 mp_add_subcheck_to_check(overall, protocol_validity_sc);
352 return OK; 360 return OK;
353 } 361 }
354 362
355 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK); 363 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
356 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string); 364 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s",
365 version_control_string);
357 mp_add_subcheck_to_check(overall, protocol_validity_sc); 366 mp_add_subcheck_to_check(overall, protocol_validity_sc);
358 367
359 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0; 368 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
@@ -368,8 +377,8 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
368 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) { 377 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
369 mp_subcheck remote_version_sc = mp_subcheck_init(); 378 mp_subcheck remote_version_sc = mp_subcheck_init();
370 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL); 379 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
371 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto, 380 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"),
372 desired_remote_version); 381 ssh_server, ssh_proto, desired_remote_version);
373 close(socket); 382 close(socket);
374 mp_add_subcheck_to_check(overall, remote_version_sc); 383 mp_add_subcheck_to_check(overall, remote_version_sc);
375 return OK; 384 return OK;
@@ -387,11 +396,13 @@ int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_
387 396
388 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) { 397 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
389 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL); 398 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL);
390 xasprintf(&protocol_version_sc.output, _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server, ssh_proto, 399 xasprintf(&protocol_version_sc.output,
391 desired_remote_protocol); 400 _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server,
401 ssh_proto, desired_remote_protocol);
392 } else { 402 } else {
393 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK); 403 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK);
394 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)", ssh_server, ssh_proto); 404 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)",
405 ssh_server, ssh_proto);
395 } 406 }
396 407
397 mp_add_subcheck_to_check(overall, protocol_version_sc); 408 mp_add_subcheck_to_check(overall, protocol_version_sc);
@@ -424,7 +435,8 @@ void print_help(void) {
424 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 435 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
425 436
426 printf(" %s\n", "-r, --remote-version=STRING"); 437 printf(" %s\n", "-r, --remote-version=STRING");
427 printf(" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)")); 438 printf(" %s\n",
439 _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
428 440
429 printf(" %s\n", "-P, --remote-protocol=STRING"); 441 printf(" %s\n", "-P, --remote-protocol=STRING");
430 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 442 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
@@ -437,5 +449,6 @@ void print_help(void) {
437 449
438void print_usage(void) { 450void print_usage(void) {
439 printf("%s\n", _("Usage:")); 451 printf("%s\n", _("Usage:"));
440 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname); 452 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n",
453 progname);
441} 454}