diff options
Diffstat (limited to 'plugins/check_ping.c')
| -rw-r--r-- | plugins/check_ping.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/plugins/check_ping.c b/plugins/check_ping.c new file mode 100644 index 00000000..b61b41b5 --- /dev/null +++ b/plugins/check_ping.c | |||
| @@ -0,0 +1,492 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * CHECK_PING.C | ||
| 4 | * | ||
| 5 | * Program: Ping plugin for Nagios | ||
| 6 | * License: GPL | ||
| 7 | * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) | ||
| 8 | * | ||
| 9 | * $Id$ | ||
| 10 | * | ||
| 11 | *****************************************************************************/ | ||
| 12 | |||
| 13 | #define PROGNAME "check_pgsql" | ||
| 14 | #define REVISION "$Revision$" | ||
| 15 | #define COPYRIGHT "1999-2001" | ||
| 16 | #define AUTHOR "Ethan Galstad/Karl DeBisschop" | ||
| 17 | #define EMAIL "kdebisschop@users.sourceforge.net" | ||
| 18 | #define SUMMARY "Use ping to check connection statistics for a remote host.\n" | ||
| 19 | |||
| 20 | #define OPTIONS "\ | ||
| 21 | -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n\ | ||
| 22 | [-p packets] [-t timeout] [-L]\n" | ||
| 23 | |||
| 24 | #define LONGOPTIONS "\ | ||
| 25 | -H, --hostname=HOST\n\ | ||
| 26 | host to ping\n\ | ||
| 27 | -w, --warning=THRESHOLD\n\ | ||
| 28 | warning threshold pair\n\ | ||
| 29 | -c, --critical=THRESHOLD\n\ | ||
| 30 | critical threshold pair\n\ | ||
| 31 | -p, --packets=INTEGER\n\ | ||
| 32 | number of ICMP ECHO packets to send (Default: %d)\n\ | ||
| 33 | -t, --timeout=INTEGER\n\ | ||
| 34 | optional specified timeout in second (Default: %d)\n\ | ||
| 35 | -L, --link\n\ | ||
| 36 | show HTML in the plugin output (obsoleted by urlize)\n\ | ||
| 37 | THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel\n\ | ||
| 38 | time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the\n\ | ||
| 39 | percentage of packet loss to trigger an alarm state.\n" | ||
| 40 | |||
| 41 | #define DESCRIPTION "\ | ||
| 42 | This plugin uses the ping command to probe the specified host for packet loss\n\ | ||
| 43 | (percentage) and round trip average (milliseconds). It can produce HTML output\n\ | ||
| 44 | linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in\n\ | ||
| 45 | the contrib area of the downloads section at http://www.nagios.org\n\n" | ||
| 46 | |||
| 47 | #include "config.h" | ||
| 48 | #include "common.h" | ||
| 49 | #include "popen.h" | ||
| 50 | #include "utils.h" | ||
| 51 | |||
| 52 | #define UNKNOWN_PACKET_LOSS 200 /* 200% */ | ||
| 53 | #define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */ | ||
| 54 | #define DEFAULT_MAX_PACKETS 5 /* default no. of ICMP ECHO packets */ | ||
| 55 | |||
| 56 | #define WARN_DUPLICATES "DUPLICATES FOUND! " | ||
| 57 | |||
| 58 | int process_arguments (int, char **); | ||
| 59 | int call_getopt (int, char **); | ||
| 60 | int get_threshold (char *, float *, int *); | ||
| 61 | int validate_arguments (void); | ||
| 62 | int run_ping (char *); | ||
| 63 | void print_usage (void); | ||
| 64 | void print_help (void); | ||
| 65 | |||
| 66 | int display_html = FALSE; | ||
| 67 | int wpl = UNKNOWN_PACKET_LOSS; | ||
| 68 | int cpl = UNKNOWN_PACKET_LOSS; | ||
| 69 | float wrta = UNKNOWN_TRIP_TIME; | ||
| 70 | float crta = UNKNOWN_TRIP_TIME; | ||
| 71 | char *server_address = NULL; | ||
| 72 | int max_packets = -1; | ||
| 73 | int verbose = FALSE; | ||
| 74 | |||
| 75 | float rta = UNKNOWN_TRIP_TIME; | ||
| 76 | int pl = UNKNOWN_PACKET_LOSS; | ||
| 77 | |||
| 78 | char *warn_text = NULL; | ||
| 79 | |||
| 80 | int | ||
| 81 | main (int argc, char **argv) | ||
| 82 | { | ||
| 83 | char *command_line = NULL; | ||
| 84 | int result = STATE_UNKNOWN; | ||
| 85 | |||
| 86 | if (process_arguments (argc, argv) == ERROR) | ||
| 87 | usage ("Could not parse arguments"); | ||
| 88 | |||
| 89 | /* does the host address of number of packets argument come first? */ | ||
| 90 | #ifdef PING_PACKETS_FIRST | ||
| 91 | command_line = | ||
| 92 | ssprintf (command_line, PING_COMMAND, max_packets, server_address); | ||
| 93 | #else | ||
| 94 | command_line = | ||
| 95 | ssprintf (command_line, PING_COMMAND, server_address, max_packets); | ||
| 96 | #endif | ||
| 97 | |||
| 98 | /* Set signal handling and alarm */ | ||
| 99 | if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { | ||
| 100 | printf ("Cannot catch SIGALRM"); | ||
| 101 | return STATE_UNKNOWN; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* handle timeouts gracefully */ | ||
| 105 | alarm (timeout_interval); | ||
| 106 | |||
| 107 | if (verbose) | ||
| 108 | printf ("%s ==> ", command_line); | ||
| 109 | |||
| 110 | /* run the command */ | ||
| 111 | run_ping (command_line); | ||
| 112 | |||
| 113 | if (pl == UNKNOWN_PACKET_LOSS || rta == UNKNOWN_TRIP_TIME) { | ||
| 114 | printf ("%s\n", command_line); | ||
| 115 | terminate (STATE_UNKNOWN, | ||
| 116 | "Error: Could not interpret output from ping command\n"); | ||
| 117 | } | ||
| 118 | |||
| 119 | if (pl >= cpl || rta >= crta || rta < 0) | ||
| 120 | result = STATE_CRITICAL; | ||
| 121 | else if (pl >= wpl || rta >= wrta) | ||
| 122 | result = STATE_WARNING; | ||
| 123 | else if (pl < wpl && rta < wrta && pl >= 0 && rta >= 0) | ||
| 124 | result = max (result, STATE_OK); | ||
| 125 | |||
| 126 | if (display_html == TRUE) | ||
| 127 | printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, server_address); | ||
| 128 | if (pl == 100) | ||
| 129 | printf ("PING %s - %sPacket loss = %d%%", state_text (result), warn_text, | ||
| 130 | pl); | ||
| 131 | else | ||
| 132 | printf ("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms", | ||
| 133 | state_text (result), warn_text, pl, rta); | ||
| 134 | if (display_html == TRUE) | ||
| 135 | printf ("</A>"); | ||
| 136 | printf ("\n"); | ||
| 137 | |||
| 138 | if (verbose) | ||
| 139 | printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); | ||
| 140 | |||
| 141 | return result; | ||
| 142 | } | ||
| 143 | |||
| 144 | |||
| 145 | /* process command-line arguments */ | ||
| 146 | int | ||
| 147 | process_arguments (int argc, char **argv) | ||
| 148 | { | ||
| 149 | int c; | ||
| 150 | |||
| 151 | if (argc < 2) | ||
| 152 | return ERROR; | ||
| 153 | |||
| 154 | for (c = 1; c < argc; c++) { | ||
| 155 | if (strcmp ("-to", argv[c]) == 0) | ||
| 156 | strcpy (argv[c], "-t"); | ||
| 157 | if (strcmp ("-nohtml", argv[c]) == 0) | ||
| 158 | strcpy (argv[c], "-n"); | ||
| 159 | } | ||
| 160 | |||
| 161 | c = 0; | ||
| 162 | while ((c += call_getopt (argc - c, &argv[c])) < argc) { | ||
| 163 | |||
| 164 | if (is_option (argv[c])) | ||
| 165 | continue; | ||
| 166 | |||
| 167 | if (server_address == NULL) { | ||
| 168 | if (is_host (argv[c]) == FALSE) { | ||
| 169 | printf ("Invalid host name/address: %s\n\n", argv[c]); | ||
| 170 | return ERROR; | ||
| 171 | } | ||
| 172 | server_address = argv[c]; | ||
| 173 | } | ||
| 174 | else if (wpl == UNKNOWN_PACKET_LOSS) { | ||
| 175 | if (is_intpercent (argv[c]) == FALSE) { | ||
| 176 | printf ("<wpl> (%s) must be an integer percentage\n", argv[c]); | ||
| 177 | return ERROR; | ||
| 178 | } | ||
| 179 | wpl = atoi (argv[c]); | ||
| 180 | } | ||
| 181 | else if (cpl == UNKNOWN_PACKET_LOSS) { | ||
| 182 | if (is_intpercent (argv[c]) == FALSE) { | ||
| 183 | printf ("<cpl> (%s) must be an integer percentage\n", argv[c]); | ||
| 184 | return ERROR; | ||
| 185 | } | ||
| 186 | cpl = atoi (argv[c]); | ||
| 187 | } | ||
| 188 | else if (wrta == UNKNOWN_TRIP_TIME) { | ||
| 189 | if (is_negative (argv[c])) { | ||
| 190 | printf ("<wrta> (%s) must be a non-negative number\n", argv[c]); | ||
| 191 | return ERROR; | ||
| 192 | } | ||
| 193 | wrta = atof (argv[c]); | ||
| 194 | } | ||
| 195 | else if (crta == UNKNOWN_TRIP_TIME) { | ||
| 196 | if (is_negative (argv[c])) { | ||
| 197 | printf ("<crta> (%s) must be a non-negative number\n", argv[c]); | ||
| 198 | return ERROR; | ||
| 199 | } | ||
| 200 | crta = atof (argv[c]); | ||
| 201 | } | ||
| 202 | else if (max_packets == -1) { | ||
| 203 | if (is_intnonneg (argv[c])) { | ||
| 204 | max_packets = atoi (argv[c]); | ||
| 205 | } | ||
| 206 | else { | ||
| 207 | printf ("<max_packets> (%s) must be a non-negative number\n", | ||
| 208 | argv[c]); | ||
| 209 | return ERROR; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | } | ||
| 214 | |||
| 215 | return validate_arguments (); | ||
| 216 | } | ||
| 217 | |||
| 218 | int | ||
| 219 | call_getopt (int argc, char **argv) | ||
| 220 | { | ||
| 221 | int c, i = 0; | ||
| 222 | |||
| 223 | #ifdef HAVE_GETOPT_H | ||
| 224 | int option_index = 0; | ||
| 225 | static struct option long_options[] = { | ||
| 226 | {"help", no_argument, 0, 'h'}, | ||
| 227 | {"version", no_argument, 0, 'V'}, | ||
| 228 | {"verbose", no_argument, 0, 'v'}, | ||
| 229 | {"nohtml", no_argument, 0, 'n'}, | ||
| 230 | {"link", no_argument, 0, 'L'}, | ||
| 231 | {"timeout", required_argument, 0, 't'}, | ||
| 232 | {"critical", required_argument, 0, 'c'}, | ||
| 233 | {"warning", required_argument, 0, 'w'}, | ||
| 234 | {"hostname", required_argument, 0, 'H'}, | ||
| 235 | {"packets", required_argument, 0, 'p'}, | ||
| 236 | {0, 0, 0, 0} | ||
| 237 | }; | ||
| 238 | #endif | ||
| 239 | |||
| 240 | while (1) { | ||
| 241 | #ifdef HAVE_GETOPT_H | ||
| 242 | c = | ||
| 243 | getopt_long (argc, argv, "+hVvt:c:w:H:p:nL", long_options, | ||
| 244 | &option_index); | ||
| 245 | #else | ||
| 246 | c = getopt (argc, argv, "+hVvt:c:w:H:p:nL"); | ||
| 247 | #endif | ||
| 248 | |||
| 249 | i++; | ||
| 250 | |||
| 251 | if (c == -1 || c == EOF || c == 1) | ||
| 252 | break; | ||
| 253 | |||
| 254 | switch (c) { | ||
| 255 | case 't': | ||
| 256 | case 'c': | ||
| 257 | case 'w': | ||
| 258 | case 'H': | ||
| 259 | case 'p': | ||
| 260 | i++; | ||
| 261 | } | ||
| 262 | |||
| 263 | switch (c) { | ||
| 264 | case '?': /* print short usage statement if args not parsable */ | ||
| 265 | usage2 ("Unknown argument", optarg); | ||
| 266 | case 'h': /* help */ | ||
| 267 | print_help (); | ||
| 268 | exit (STATE_OK); | ||
| 269 | case 'V': /* version */ | ||
| 270 | print_revision (PROGNAME, REVISION); | ||
| 271 | exit (STATE_OK); | ||
| 272 | case 't': /* timeout period */ | ||
| 273 | timeout_interval = atoi (optarg); | ||
| 274 | break; | ||
| 275 | case 'v': /* verbose mode */ | ||
| 276 | verbose = TRUE; | ||
| 277 | break; | ||
| 278 | case 'H': /* hostname */ | ||
| 279 | if (is_host (optarg) == FALSE) | ||
| 280 | usage2 ("Invalid host name/address", optarg); | ||
| 281 | server_address = optarg; | ||
| 282 | break; | ||
| 283 | case 'p': /* number of packets to send */ | ||
| 284 | if (is_intnonneg (optarg)) | ||
| 285 | max_packets = atoi (optarg); | ||
| 286 | else | ||
| 287 | usage2 ("<max_packets> (%s) must be a non-negative number\n", optarg); | ||
| 288 | break; | ||
| 289 | case 'n': /* no HTML */ | ||
| 290 | display_html = FALSE; | ||
| 291 | break; | ||
| 292 | case 'L': /* show HTML */ | ||
| 293 | display_html = TRUE; | ||
| 294 | break; | ||
| 295 | case 'c': | ||
| 296 | get_threshold (optarg, &crta, &cpl); | ||
| 297 | break; | ||
| 298 | case 'w': | ||
| 299 | get_threshold (optarg, &wrta, &wpl); | ||
| 300 | break; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | return i; | ||
| 305 | } | ||
| 306 | |||
| 307 | int | ||
| 308 | get_threshold (char *arg, float *trta, int *tpl) | ||
| 309 | { | ||
| 310 | if (is_intnonneg (arg) && sscanf (arg, "%f", trta) == 1) | ||
| 311 | return OK; | ||
| 312 | else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2) | ||
| 313 | return OK; | ||
| 314 | else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1) | ||
| 315 | return OK; | ||
| 316 | else | ||
| 317 | usage2 ("%s: Warning threshold must be integer or percentage!\n\n", arg); | ||
| 318 | |||
| 319 | } | ||
| 320 | |||
| 321 | int | ||
| 322 | validate_arguments () | ||
| 323 | { | ||
| 324 | float max_seconds; | ||
| 325 | |||
| 326 | if (wrta == UNKNOWN_TRIP_TIME) { | ||
| 327 | printf ("<wrta> was not set\n"); | ||
| 328 | return ERROR; | ||
| 329 | } | ||
| 330 | else if (crta == UNKNOWN_TRIP_TIME) { | ||
| 331 | printf ("<crta> was not set\n"); | ||
| 332 | return ERROR; | ||
| 333 | } | ||
| 334 | else if (wpl == UNKNOWN_PACKET_LOSS) { | ||
| 335 | printf ("<wpl> was not set\n"); | ||
| 336 | return ERROR; | ||
| 337 | } | ||
| 338 | else if (cpl == UNKNOWN_PACKET_LOSS) { | ||
| 339 | printf ("<cpl> was not set\n"); | ||
| 340 | return ERROR; | ||
| 341 | } | ||
| 342 | else if (wrta > crta) { | ||
| 343 | printf ("<wrta> (%f) cannot be larger than <crta> (%f)\n", wrta, crta); | ||
| 344 | return ERROR; | ||
| 345 | } | ||
| 346 | else if (wpl > cpl) { | ||
| 347 | printf ("<wpl> (%d) cannot be larger than <cpl> (%d)\n", wpl, cpl); | ||
| 348 | return ERROR; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (max_packets == -1) | ||
| 352 | max_packets = DEFAULT_MAX_PACKETS; | ||
| 353 | |||
| 354 | max_seconds = crta / 1000.0 * max_packets + max_packets; | ||
| 355 | if (max_seconds > timeout_interval) | ||
| 356 | timeout_interval = (int)max_seconds; | ||
| 357 | |||
| 358 | return OK; | ||
| 359 | } | ||
| 360 | |||
| 361 | |||
| 362 | int | ||
| 363 | run_ping (char *command_line) | ||
| 364 | { | ||
| 365 | char input_buffer[MAX_INPUT_BUFFER]; | ||
| 366 | int result = STATE_UNKNOWN; | ||
| 367 | |||
| 368 | warn_text = malloc (1); | ||
| 369 | if (warn_text == NULL) | ||
| 370 | terminate (STATE_UNKNOWN, "unable to malloc warn_text"); | ||
| 371 | warn_text[0] = 0; | ||
| 372 | |||
| 373 | if ((child_process = spopen (command_line)) == NULL) { | ||
| 374 | printf ("Cannot open pipe: "); | ||
| 375 | terminate (STATE_UNKNOWN, command_line); | ||
| 376 | } | ||
| 377 | child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); | ||
| 378 | if (child_stderr == NULL) | ||
| 379 | printf ("Cannot open stderr for %s\n", command_line); | ||
| 380 | |||
| 381 | while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { | ||
| 382 | |||
| 383 | if (strstr (input_buffer, "(DUP!)")) { | ||
| 384 | result = max (result, STATE_WARNING); | ||
| 385 | warn_text = realloc (warn_text, strlen (WARN_DUPLICATES) + 1); | ||
| 386 | if (warn_text == NULL) | ||
| 387 | terminate (STATE_UNKNOWN, "unable to realloc warn_text"); | ||
| 388 | strcpy (warn_text, WARN_DUPLICATES); | ||
| 389 | } | ||
| 390 | |||
| 391 | /* get the percent loss statistics */ | ||
| 392 | if (sscanf | ||
| 393 | (input_buffer, | ||
| 394 | "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss", | ||
| 395 | &pl) == 1 | ||
| 396 | || sscanf (input_buffer, | ||
| 397 | "%*d packets transmitted, %*d packets received, %d%% packet loss", | ||
| 398 | &pl) == 1) | ||
| 399 | continue; | ||
| 400 | |||
| 401 | /* get the round trip average */ | ||
| 402 | else | ||
| 403 | if (sscanf (input_buffer, "round-trip min/avg/max = %*f/%f/%*f", &rta) | ||
| 404 | == 1 | ||
| 405 | || sscanf (input_buffer, | ||
| 406 | "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f", | ||
| 407 | &rta) == 1 | ||
| 408 | || sscanf (input_buffer, | ||
| 409 | "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f", | ||
| 410 | &rta) == 1 | ||
| 411 | || sscanf (input_buffer, | ||
| 412 | "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f", | ||
| 413 | &rta) == 1 | ||
| 414 | || sscanf (input_buffer, | ||
| 415 | "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f", | ||
| 416 | &rta) == 1 | ||
| 417 | || sscanf (input_buffer, "round-trip (ms) min/avg/max = %*f/%f/%*f", | ||
| 418 | &rta) == 1) | ||
| 419 | continue; | ||
| 420 | } | ||
| 421 | |||
| 422 | /* this is needed because there is no rta if all packets are lost */ | ||
| 423 | if (pl == 100) | ||
| 424 | rta = crta; | ||
| 425 | |||
| 426 | |||
| 427 | /* check stderr */ | ||
| 428 | while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { | ||
| 429 | if (strstr | ||
| 430 | (input_buffer, | ||
| 431 | "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP")) | ||
| 432 | continue; | ||
| 433 | |||
| 434 | if (strstr (input_buffer, "Network is unreachable")) | ||
| 435 | terminate (STATE_CRITICAL, "PING CRITICAL - Network unreachable (%s)", | ||
| 436 | server_address); | ||
| 437 | else if (strstr (input_buffer, "Destination Host Unreachable")) | ||
| 438 | terminate (STATE_CRITICAL, "PING CRITICAL - Host Unreachable (%s)", | ||
| 439 | server_address); | ||
| 440 | |||
| 441 | warn_text = | ||
| 442 | realloc (warn_text, strlen (warn_text) + strlen (input_buffer) + 2); | ||
| 443 | if (warn_text == NULL) | ||
| 444 | terminate (STATE_UNKNOWN, "unable to realloc warn_text"); | ||
| 445 | if (strlen (warn_text) == 0) | ||
| 446 | strcpy (warn_text, input_buffer); | ||
| 447 | else | ||
| 448 | sprintf (warn_text, "%s %s", warn_text, input_buffer); | ||
| 449 | |||
| 450 | if (strstr (input_buffer, "DUPLICATES FOUND")) | ||
| 451 | result = max (result, STATE_WARNING); | ||
| 452 | else | ||
| 453 | result = max (result, STATE_CRITICAL); | ||
| 454 | } | ||
| 455 | (void) fclose (child_stderr); | ||
| 456 | |||
| 457 | |||
| 458 | /* close the pipe - WARNING if status is set */ | ||
| 459 | if (spclose (child_process)) | ||
| 460 | result = max (result, STATE_WARNING); | ||
| 461 | |||
| 462 | return result; | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 466 | void | ||
| 467 | print_usage (void) | ||
| 468 | { | ||
| 469 | printf ("Usage:\n" " %s %s\n" | ||
| 470 | #ifdef HAVE_GETOPT_H | ||
| 471 | " %s (-h | --help) for detailed help\n" | ||
| 472 | " %s (-V | --version) for version information\n", | ||
| 473 | #else | ||
| 474 | " %s -h for detailed help\n" | ||
| 475 | " %s -V for version information\n", | ||
| 476 | #endif | ||
| 477 | PROGNAME, OPTIONS, PROGNAME, PROGNAME); | ||
| 478 | } | ||
| 479 | |||
| 480 | void | ||
| 481 | print_help (void) | ||
| 482 | { | ||
| 483 | print_revision (PROGNAME, REVISION); | ||
| 484 | printf | ||
| 485 | ("Copyright (c) %s %s <%s>\n\n%s\n", | ||
| 486 | COPYRIGHT, AUTHOR, EMAIL, SUMMARY); | ||
| 487 | print_usage (); | ||
| 488 | printf | ||
| 489 | ("\nOptions:\n" LONGOPTIONS "\n" DESCRIPTION "\n", | ||
| 490 | DEFAULT_MAX_PACKETS, DEFAULT_SOCKET_TIMEOUT); | ||
| 491 | support (); | ||
| 492 | } | ||
