summaryrefslogtreecommitdiffstats
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 @@
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\
37THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel\n\
38time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the\n\
39percentage of packet loss to trigger an alarm state.\n"
40
41#define DESCRIPTION "\
42This 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\
44linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in\n\
45the 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
58int process_arguments (int, char **);
59int call_getopt (int, char **);
60int get_threshold (char *, float *, int *);
61int validate_arguments (void);
62int run_ping (char *);
63void print_usage (void);
64void print_help (void);
65
66int display_html = FALSE;
67int wpl = UNKNOWN_PACKET_LOSS;
68int cpl = UNKNOWN_PACKET_LOSS;
69float wrta = UNKNOWN_TRIP_TIME;
70float crta = UNKNOWN_TRIP_TIME;
71char *server_address = NULL;
72int max_packets = -1;
73int verbose = FALSE;
74
75float rta = UNKNOWN_TRIP_TIME;
76int pl = UNKNOWN_PACKET_LOSS;
77
78char *warn_text = NULL;
79
80int
81main (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 */
146int
147process_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
218int
219call_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
307int
308get_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
321int
322validate_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
362int
363run_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
466void
467print_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
480void
481print_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}