aboutsummaryrefslogtreecommitdiff
path: root/plugins/check_ping.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_ping.c')
-rw-r--r--plugins/check_ping.c492
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 @@
+/*****************************************************************************
+*
+* CHECK_PING.C
+*
+* Program: Ping plugin for Nagios
+* License: GPL
+* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
+*
+* $Id$
+*
+*****************************************************************************/
+
+#define PROGNAME "check_pgsql"
+#define REVISION "$Revision$"
+#define COPYRIGHT "1999-2001"
+#define AUTHOR "Ethan Galstad/Karl DeBisschop"
+#define EMAIL "kdebisschop@users.sourceforge.net"
+#define SUMMARY "Use ping to check connection statistics for a remote host.\n"
+
+#define OPTIONS "\
+-H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n\
+ [-p packets] [-t timeout] [-L]\n"
+
+#define LONGOPTIONS "\
+-H, --hostname=HOST\n\
+ host to ping\n\
+-w, --warning=THRESHOLD\n\
+ warning threshold pair\n\
+-c, --critical=THRESHOLD\n\
+ critical threshold pair\n\
+-p, --packets=INTEGER\n\
+ number of ICMP ECHO packets to send (Default: %d)\n\
+-t, --timeout=INTEGER\n\
+ optional specified timeout in second (Default: %d)\n\
+-L, --link\n\
+ show HTML in the plugin output (obsoleted by urlize)\n\
+THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel\n\
+time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the\n\
+percentage of packet loss to trigger an alarm state.\n"
+
+#define DESCRIPTION "\
+This plugin uses the ping command to probe the specified host for packet loss\n\
+(percentage) and round trip average (milliseconds). It can produce HTML output\n\
+linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in\n\
+the contrib area of the downloads section at http://www.nagios.org\n\n"
+
+#include "config.h"
+#include "common.h"
+#include "popen.h"
+#include "utils.h"
+
+#define UNKNOWN_PACKET_LOSS 200 /* 200% */
+#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
+#define DEFAULT_MAX_PACKETS 5 /* default no. of ICMP ECHO packets */
+
+#define WARN_DUPLICATES "DUPLICATES FOUND! "
+
+int process_arguments (int, char **);
+int call_getopt (int, char **);
+int get_threshold (char *, float *, int *);
+int validate_arguments (void);
+int run_ping (char *);
+void print_usage (void);
+void print_help (void);
+
+int display_html = FALSE;
+int wpl = UNKNOWN_PACKET_LOSS;
+int cpl = UNKNOWN_PACKET_LOSS;
+float wrta = UNKNOWN_TRIP_TIME;
+float crta = UNKNOWN_TRIP_TIME;
+char *server_address = NULL;
+int max_packets = -1;
+int verbose = FALSE;
+
+float rta = UNKNOWN_TRIP_TIME;
+int pl = UNKNOWN_PACKET_LOSS;
+
+char *warn_text = NULL;
+
+int
+main (int argc, char **argv)
+{
+ char *command_line = NULL;
+ int result = STATE_UNKNOWN;
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage ("Could not parse arguments");
+
+ /* does the host address of number of packets argument come first? */
+#ifdef PING_PACKETS_FIRST
+ command_line =
+ ssprintf (command_line, PING_COMMAND, max_packets, server_address);
+#else
+ command_line =
+ ssprintf (command_line, PING_COMMAND, server_address, max_packets);
+#endif
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
+ printf ("Cannot catch SIGALRM");
+ return STATE_UNKNOWN;
+ }
+
+ /* handle timeouts gracefully */
+ alarm (timeout_interval);
+
+ if (verbose)
+ printf ("%s ==> ", command_line);
+
+ /* run the command */
+ run_ping (command_line);
+
+ if (pl == UNKNOWN_PACKET_LOSS || rta == UNKNOWN_TRIP_TIME) {
+ printf ("%s\n", command_line);
+ terminate (STATE_UNKNOWN,
+ "Error: Could not interpret output from ping command\n");
+ }
+
+ if (pl >= cpl || rta >= crta || rta < 0)
+ result = STATE_CRITICAL;
+ else if (pl >= wpl || rta >= wrta)
+ result = STATE_WARNING;
+ else if (pl < wpl && rta < wrta && pl >= 0 && rta >= 0)
+ result = max (result, STATE_OK);
+
+ if (display_html == TRUE)
+ printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, server_address);
+ if (pl == 100)
+ printf ("PING %s - %sPacket loss = %d%%", state_text (result), warn_text,
+ pl);
+ else
+ printf ("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms",
+ state_text (result), warn_text, pl, rta);
+ if (display_html == TRUE)
+ printf ("</A>");
+ printf ("\n");
+
+ if (verbose)
+ printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl);
+
+ return result;
+}
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ if (strcmp ("-nohtml", argv[c]) == 0)
+ strcpy (argv[c], "-n");
+ }
+
+ c = 0;
+ while ((c += call_getopt (argc - c, &argv[c])) < argc) {
+
+ if (is_option (argv[c]))
+ continue;
+
+ if (server_address == NULL) {
+ if (is_host (argv[c]) == FALSE) {
+ printf ("Invalid host name/address: %s\n\n", argv[c]);
+ return ERROR;
+ }
+ server_address = argv[c];
+ }
+ else if (wpl == UNKNOWN_PACKET_LOSS) {
+ if (is_intpercent (argv[c]) == FALSE) {
+ printf ("<wpl> (%s) must be an integer percentage\n", argv[c]);
+ return ERROR;
+ }
+ wpl = atoi (argv[c]);
+ }
+ else if (cpl == UNKNOWN_PACKET_LOSS) {
+ if (is_intpercent (argv[c]) == FALSE) {
+ printf ("<cpl> (%s) must be an integer percentage\n", argv[c]);
+ return ERROR;
+ }
+ cpl = atoi (argv[c]);
+ }
+ else if (wrta == UNKNOWN_TRIP_TIME) {
+ if (is_negative (argv[c])) {
+ printf ("<wrta> (%s) must be a non-negative number\n", argv[c]);
+ return ERROR;
+ }
+ wrta = atof (argv[c]);
+ }
+ else if (crta == UNKNOWN_TRIP_TIME) {
+ if (is_negative (argv[c])) {
+ printf ("<crta> (%s) must be a non-negative number\n", argv[c]);
+ return ERROR;
+ }
+ crta = atof (argv[c]);
+ }
+ else if (max_packets == -1) {
+ if (is_intnonneg (argv[c])) {
+ max_packets = atoi (argv[c]);
+ }
+ else {
+ printf ("<max_packets> (%s) must be a non-negative number\n",
+ argv[c]);
+ return ERROR;
+ }
+ }
+
+ }
+
+ return validate_arguments ();
+}
+
+int
+call_getopt (int argc, char **argv)
+{
+ int c, i = 0;
+
+#ifdef HAVE_GETOPT_H
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"nohtml", no_argument, 0, 'n'},
+ {"link", no_argument, 0, 'L'},
+ {"timeout", required_argument, 0, 't'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"hostname", required_argument, 0, 'H'},
+ {"packets", required_argument, 0, 'p'},
+ {0, 0, 0, 0}
+ };
+#endif
+
+ while (1) {
+#ifdef HAVE_GETOPT_H
+ c =
+ getopt_long (argc, argv, "+hVvt:c:w:H:p:nL", long_options,
+ &option_index);
+#else
+ c = getopt (argc, argv, "+hVvt:c:w:H:p:nL");
+#endif
+
+ i++;
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 't':
+ case 'c':
+ case 'w':
+ case 'H':
+ case 'p':
+ i++;
+ }
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage2 ("Unknown argument", optarg);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_OK);
+ case 'V': /* version */
+ print_revision (PROGNAME, REVISION);
+ exit (STATE_OK);
+ case 't': /* timeout period */
+ timeout_interval = atoi (optarg);
+ break;
+ case 'v': /* verbose mode */
+ verbose = TRUE;
+ break;
+ case 'H': /* hostname */
+ if (is_host (optarg) == FALSE)
+ usage2 ("Invalid host name/address", optarg);
+ server_address = optarg;
+ break;
+ case 'p': /* number of packets to send */
+ if (is_intnonneg (optarg))
+ max_packets = atoi (optarg);
+ else
+ usage2 ("<max_packets> (%s) must be a non-negative number\n", optarg);
+ break;
+ case 'n': /* no HTML */
+ display_html = FALSE;
+ break;
+ case 'L': /* show HTML */
+ display_html = TRUE;
+ break;
+ case 'c':
+ get_threshold (optarg, &crta, &cpl);
+ break;
+ case 'w':
+ get_threshold (optarg, &wrta, &wpl);
+ break;
+ }
+ }
+
+ return i;
+}
+
+int
+get_threshold (char *arg, float *trta, int *tpl)
+{
+ if (is_intnonneg (arg) && sscanf (arg, "%f", trta) == 1)
+ return OK;
+ else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2)
+ return OK;
+ else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1)
+ return OK;
+ else
+ usage2 ("%s: Warning threshold must be integer or percentage!\n\n", arg);
+
+}
+
+int
+validate_arguments ()
+{
+ float max_seconds;
+
+ if (wrta == UNKNOWN_TRIP_TIME) {
+ printf ("<wrta> was not set\n");
+ return ERROR;
+ }
+ else if (crta == UNKNOWN_TRIP_TIME) {
+ printf ("<crta> was not set\n");
+ return ERROR;
+ }
+ else if (wpl == UNKNOWN_PACKET_LOSS) {
+ printf ("<wpl> was not set\n");
+ return ERROR;
+ }
+ else if (cpl == UNKNOWN_PACKET_LOSS) {
+ printf ("<cpl> was not set\n");
+ return ERROR;
+ }
+ else if (wrta > crta) {
+ printf ("<wrta> (%f) cannot be larger than <crta> (%f)\n", wrta, crta);
+ return ERROR;
+ }
+ else if (wpl > cpl) {
+ printf ("<wpl> (%d) cannot be larger than <cpl> (%d)\n", wpl, cpl);
+ return ERROR;
+ }
+
+ if (max_packets == -1)
+ max_packets = DEFAULT_MAX_PACKETS;
+
+ max_seconds = crta / 1000.0 * max_packets + max_packets;
+ if (max_seconds > timeout_interval)
+ timeout_interval = (int)max_seconds;
+
+ return OK;
+}
+
+
+int
+run_ping (char *command_line)
+{
+ char input_buffer[MAX_INPUT_BUFFER];
+ int result = STATE_UNKNOWN;
+
+ warn_text = malloc (1);
+ if (warn_text == NULL)
+ terminate (STATE_UNKNOWN, "unable to malloc warn_text");
+ warn_text[0] = 0;
+
+ if ((child_process = spopen (command_line)) == NULL) {
+ printf ("Cannot open pipe: ");
+ terminate (STATE_UNKNOWN, command_line);
+ }
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL)
+ printf ("Cannot open stderr for %s\n", command_line);
+
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
+
+ if (strstr (input_buffer, "(DUP!)")) {
+ result = max (result, STATE_WARNING);
+ warn_text = realloc (warn_text, strlen (WARN_DUPLICATES) + 1);
+ if (warn_text == NULL)
+ terminate (STATE_UNKNOWN, "unable to realloc warn_text");
+ strcpy (warn_text, WARN_DUPLICATES);
+ }
+
+ /* get the percent loss statistics */
+ if (sscanf
+ (input_buffer,
+ "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss",
+ &pl) == 1
+ || sscanf (input_buffer,
+ "%*d packets transmitted, %*d packets received, %d%% packet loss",
+ &pl) == 1)
+ continue;
+
+ /* get the round trip average */
+ else
+ if (sscanf (input_buffer, "round-trip min/avg/max = %*f/%f/%*f", &rta)
+ == 1
+ || sscanf (input_buffer,
+ "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f",
+ &rta) == 1
+ || sscanf (input_buffer,
+ "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f",
+ &rta) == 1
+ || sscanf (input_buffer,
+ "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f",
+ &rta) == 1
+ || sscanf (input_buffer,
+ "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f",
+ &rta) == 1
+ || sscanf (input_buffer, "round-trip (ms) min/avg/max = %*f/%f/%*f",
+ &rta) == 1)
+ continue;
+ }
+
+ /* this is needed because there is no rta if all packets are lost */
+ if (pl == 100)
+ rta = crta;
+
+
+ /* check stderr */
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
+ if (strstr
+ (input_buffer,
+ "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP"))
+ continue;
+
+ if (strstr (input_buffer, "Network is unreachable"))
+ terminate (STATE_CRITICAL, "PING CRITICAL - Network unreachable (%s)",
+ server_address);
+ else if (strstr (input_buffer, "Destination Host Unreachable"))
+ terminate (STATE_CRITICAL, "PING CRITICAL - Host Unreachable (%s)",
+ server_address);
+
+ warn_text =
+ realloc (warn_text, strlen (warn_text) + strlen (input_buffer) + 2);
+ if (warn_text == NULL)
+ terminate (STATE_UNKNOWN, "unable to realloc warn_text");
+ if (strlen (warn_text) == 0)
+ strcpy (warn_text, input_buffer);
+ else
+ sprintf (warn_text, "%s %s", warn_text, input_buffer);
+
+ if (strstr (input_buffer, "DUPLICATES FOUND"))
+ result = max (result, STATE_WARNING);
+ else
+ result = max (result, STATE_CRITICAL);
+ }
+ (void) fclose (child_stderr);
+
+
+ /* close the pipe - WARNING if status is set */
+ if (spclose (child_process))
+ result = max (result, STATE_WARNING);
+
+ return result;
+}
+
+
+void
+print_usage (void)
+{
+ printf ("Usage:\n" " %s %s\n"
+#ifdef HAVE_GETOPT_H
+ " %s (-h | --help) for detailed help\n"
+ " %s (-V | --version) for version information\n",
+#else
+ " %s -h for detailed help\n"
+ " %s -V for version information\n",
+#endif
+ PROGNAME, OPTIONS, PROGNAME, PROGNAME);
+}
+
+void
+print_help (void)
+{
+ print_revision (PROGNAME, REVISION);
+ printf
+ ("Copyright (c) %s %s <%s>\n\n%s\n",
+ COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
+ print_usage ();
+ printf
+ ("\nOptions:\n" LONGOPTIONS "\n" DESCRIPTION "\n",
+ DEFAULT_MAX_PACKETS, DEFAULT_SOCKET_TIMEOUT);
+ support ();
+}