diff options
author | Ethan Galstad <egalstad@users.sourceforge.net> | 2002-02-28 06:42:51 +0000 |
---|---|---|
committer | Ethan Galstad <egalstad@users.sourceforge.net> | 2002-02-28 06:42:51 +0000 |
commit | 44a321cb8a42d6c0ea2d96a1086a17f2134c89cc (patch) | |
tree | a1a4d9f7b92412a17ab08f34f04eec45433048b7 /plugins/check_ping.c | |
parent | 54fd5d7022ff2d6a59bc52b8869182f3fc77a058 (diff) | |
download | monitoring-plugins-44a321cb8a42d6c0ea2d96a1086a17f2134c89cc.tar.gz |
Initial revision
git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@2 f882894a-f735-0410-b71e-b25c423dba1c
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 | } | ||