Merge pull request #1563 from jacobbaungard/ipv6_check_icmp
[monitoring-plugins.git] / plugins / check_fping.c
blob521d0fef69f24aca0bfee2789334a56636b1ca2d
1 /*****************************************************************************
2 *
3 * Monitoring check_fping plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2007 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_disk plugin
12 * This plugin will use the fping command to ping the specified host for a
13 * fast check
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 *****************************************************************************/
32 const char *progname = "check_fping";
33 const char *copyright = "2000-2007";
34 const char *email = "devel@monitoring-plugins.org";
36 #include "common.h"
37 #include "popen.h"
38 #include "netutils.h"
39 #include "utils.h"
41 enum {
42 PACKET_COUNT = 1,
43 PACKET_SIZE = 56,
44 PL = 0,
45 RTA = 1
48 int textscan (char *buf);
49 int process_arguments (int, char **);
50 int get_threshold (char *arg, char *rv[2]);
51 void print_help (void);
52 void print_usage (void);
54 char *server_name = NULL;
55 char *sourceip = NULL;
56 char *sourceif = NULL;
57 int packet_size = PACKET_SIZE;
58 int packet_count = PACKET_COUNT;
59 int target_timeout = 0;
60 int packet_interval = 0;
61 int verbose = FALSE;
62 int cpl;
63 int wpl;
64 double crta;
65 double wrta;
66 int cpl_p = FALSE;
67 int wpl_p = FALSE;
68 int crta_p = FALSE;
69 int wrta_p = FALSE;
71 int
72 main (int argc, char **argv)
74 /* normaly should be int result = STATE_UNKNOWN; */
76 int status = STATE_UNKNOWN;
77 int result = 0;
78 char *fping_prog = NULL;
79 char *server = NULL;
80 char *command_line = NULL;
81 char *input_buffer = NULL;
82 char *option_string = "";
83 input_buffer = malloc (MAX_INPUT_BUFFER);
85 setlocale (LC_ALL, "");
86 bindtextdomain (PACKAGE, LOCALEDIR);
87 textdomain (PACKAGE);
89 /* Parse extra opts if any */
90 argv=np_extra_opts (&argc, argv, progname);
92 if (process_arguments (argc, argv) == ERROR)
93 usage4 (_("Could not parse arguments"));
95 server = strscpy (server, server_name);
97 /* compose the command */
98 if (target_timeout)
99 xasprintf(&option_string, "%s-t %d ", option_string, target_timeout);
100 if (packet_interval)
101 xasprintf(&option_string, "%s-p %d ", option_string, packet_interval);
102 if (sourceip)
103 xasprintf(&option_string, "%s-S %s ", option_string, sourceip);
104 if (sourceif)
105 xasprintf(&option_string, "%s-I %s ", option_string, sourceif);
107 #ifdef PATH_TO_FPING6
108 if (address_family != AF_INET && is_inet6_addr(server))
109 fping_prog = strdup(PATH_TO_FPING6);
110 else
111 fping_prog = strdup(PATH_TO_FPING);
112 #else
113 fping_prog = strdup(PATH_TO_FPING);
114 #endif
116 xasprintf (&command_line, "%s %s-b %d -c %d %s", fping_prog,
117 option_string, packet_size, packet_count, server);
119 if (verbose)
120 printf ("%s\n", command_line);
122 /* run the command */
123 child_process = spopen (command_line);
124 if (child_process == NULL) {
125 printf (_("Could not open pipe: %s\n"), command_line);
126 return STATE_UNKNOWN;
129 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
130 if (child_stderr == NULL) {
131 printf (_("Could not open stderr for %s\n"), command_line);
134 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
135 if (verbose)
136 printf ("%s", input_buffer);
137 status = max_state (status, textscan (input_buffer));
140 /* If we get anything on STDERR, at least set warning */
141 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
142 status = max_state (status, STATE_WARNING);
143 if (verbose)
144 printf ("%s", input_buffer);
145 status = max_state (status, textscan (input_buffer));
147 (void) fclose (child_stderr);
149 /* close the pipe */
150 if (result = spclose (child_process))
151 /* need to use max_state not max */
152 status = max_state (status, STATE_WARNING);
154 if (result > 1 ) {
155 status = max_state (status, STATE_UNKNOWN);
156 if (result == 2) {
157 die (STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n"));
159 if (result == 3) {
160 die (STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n"));
162 if (result == 4) {
163 die (STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n"));
168 printf ("FPING %s - %s\n", state_text (status), server_name);
170 return status;
176 textscan (char *buf)
178 char *rtastr = NULL;
179 char *losstr = NULL;
180 char *xmtstr = NULL;
181 double loss;
182 double rta;
183 double xmt;
184 int status = STATE_UNKNOWN;
186 if (strstr (buf, "not found")) {
187 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
190 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) {
191 die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"),
192 "host");
195 else if (strstr (buf, "Operation not permitted") || strstr (buf, "No such device") ) {
196 die (STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"),
197 "host");
199 else if (strstr (buf, "is down")) {
200 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
203 else if (strstr (buf, "is alive")) {
204 status = STATE_OK;
207 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) {
208 losstr = strstr (buf, "=");
209 losstr = 1 + strstr (losstr, "/");
210 losstr = 1 + strstr (losstr, "/");
211 rtastr = strstr (buf, "min/avg/max");
212 rtastr = strstr (rtastr, "=");
213 rtastr = 1 + index (rtastr, '/');
214 loss = strtod (losstr, NULL);
215 rta = strtod (rtastr, NULL);
216 if (cpl_p == TRUE && loss > cpl)
217 status = STATE_CRITICAL;
218 else if (crta_p == TRUE && rta > crta)
219 status = STATE_CRITICAL;
220 else if (wpl_p == TRUE && loss > wpl)
221 status = STATE_WARNING;
222 else if (wrta_p == TRUE && rta > wrta)
223 status = STATE_WARNING;
224 else
225 status = STATE_OK;
226 die (status,
227 _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"),
228 state_text (status), server_name, loss, rta,
229 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100),
230 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, TRUE, 0, FALSE, 0));
233 else if(strstr (buf, "xmt/rcv/%loss") ) {
234 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
235 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
236 losstr = strstr (buf, "=");
237 xmtstr = 1 + losstr;
238 xmt = strtod (xmtstr, NULL);
239 if(xmt == 0)
240 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
241 losstr = 1 + strstr (losstr, "/");
242 losstr = 1 + strstr (losstr, "/");
243 loss = strtod (losstr, NULL);
244 if (atoi(losstr) == 100)
245 status = STATE_CRITICAL;
246 else if (cpl_p == TRUE && loss > cpl)
247 status = STATE_CRITICAL;
248 else if (wpl_p == TRUE && loss > wpl)
249 status = STATE_WARNING;
250 else
251 status = STATE_OK;
252 /* loss=%.0f%%;%d;%d;0;100 */
253 die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"),
254 state_text (status), server_name, loss ,
255 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100));
258 else {
259 status = max_state (status, STATE_WARNING);
262 return status;
267 /* process command-line arguments */
269 process_arguments (int argc, char **argv)
271 int c;
272 char *rv[2];
274 int option = 0;
275 static struct option longopts[] = {
276 {"hostname", required_argument, 0, 'H'},
277 {"sourceip", required_argument, 0, 'S'},
278 {"sourceif", required_argument, 0, 'I'},
279 {"critical", required_argument, 0, 'c'},
280 {"warning", required_argument, 0, 'w'},
281 {"bytes", required_argument, 0, 'b'},
282 {"number", required_argument, 0, 'n'},
283 {"target-timeout", required_argument, 0, 'T'},
284 {"interval", required_argument, 0, 'i'},
285 {"verbose", no_argument, 0, 'v'},
286 {"version", no_argument, 0, 'V'},
287 {"help", no_argument, 0, 'h'},
288 {"use-ipv4", no_argument, 0, '4'},
289 {"use-ipv6", no_argument, 0, '6'},
290 {0, 0, 0, 0}
293 rv[PL] = NULL;
294 rv[RTA] = NULL;
296 if (argc < 2)
297 return ERROR;
299 if (!is_option (argv[1])) {
300 server_name = argv[1];
301 argv[1] = argv[0];
302 argv = &argv[1];
303 argc--;
306 while (1) {
307 c = getopt_long (argc, argv, "+hVvH:S:c:w:b:n:T:i:I:46", longopts, &option);
309 if (c == -1 || c == EOF || c == 1)
310 break;
312 switch (c) {
313 case '?': /* print short usage statement if args not parsable */
314 usage5 ();
315 case 'h': /* help */
316 print_help ();
317 exit (STATE_UNKNOWN);
318 case 'V': /* version */
319 print_revision (progname, NP_VERSION);
320 exit (STATE_UNKNOWN);
321 case 'v': /* verbose mode */
322 verbose = TRUE;
323 break;
324 case 'H': /* hostname */
325 if (is_host (optarg) == FALSE) {
326 usage2 (_("Invalid hostname/address"), optarg);
328 server_name = strscpy (server_name, optarg);
329 break;
330 case 'S': /* sourceip */
331 if (is_host (optarg) == FALSE) {
332 usage2 (_("Invalid hostname/address"), optarg);
334 sourceip = strscpy (sourceip, optarg);
335 break;
336 case 'I': /* sourceip */
337 sourceif = strscpy (sourceif, optarg);
338 case '4': /* IPv4 only */
339 address_family = AF_INET;
340 break;
341 case '6': /* IPv6 only */
342 #ifdef USE_IPV6
343 address_family = AF_INET6;
344 #else
345 usage (_("IPv6 support not available\n"));
346 #endif
347 break;
348 case 'c':
349 get_threshold (optarg, rv);
350 if (rv[RTA]) {
351 crta = strtod (rv[RTA], NULL);
352 crta_p = TRUE;
353 rv[RTA] = NULL;
355 if (rv[PL]) {
356 cpl = atoi (rv[PL]);
357 cpl_p = TRUE;
358 rv[PL] = NULL;
360 break;
361 case 'w':
362 get_threshold (optarg, rv);
363 if (rv[RTA]) {
364 wrta = strtod (rv[RTA], NULL);
365 wrta_p = TRUE;
366 rv[RTA] = NULL;
368 if (rv[PL]) {
369 wpl = atoi (rv[PL]);
370 wpl_p = TRUE;
371 rv[PL] = NULL;
373 break;
374 case 'b': /* bytes per packet */
375 if (is_intpos (optarg))
376 packet_size = atoi (optarg);
377 else
378 usage (_("Packet size must be a positive integer"));
379 break;
380 case 'n': /* number of packets */
381 if (is_intpos (optarg))
382 packet_count = atoi (optarg);
383 else
384 usage (_("Packet count must be a positive integer"));
385 break;
386 case 'T': /* timeout in msec */
387 if (is_intpos (optarg))
388 target_timeout = atoi (optarg);
389 else
390 usage (_("Target timeout must be a positive integer"));
391 break;
392 case 'i': /* interval in msec */
393 if (is_intpos (optarg))
394 packet_interval = atoi (optarg);
395 else
396 usage (_("Interval must be a positive integer"));
397 break;
401 if (server_name == NULL)
402 usage4 (_("Hostname was not supplied"));
404 return OK;
409 get_threshold (char *arg, char *rv[2])
411 char *arg1 = NULL;
412 char *arg2 = NULL;
414 arg1 = strscpy (arg1, arg);
415 if (strpbrk (arg1, ",:"))
416 arg2 = 1 + strpbrk (arg1, ",:");
418 if (arg2) {
419 arg1[strcspn (arg1, ",:")] = 0;
420 if (strstr (arg1, "%") && strstr (arg2, "%"))
421 die (STATE_UNKNOWN,
422 _("%s: Only one threshold may be packet loss (%s)\n"), progname,
423 arg);
424 if (!strstr (arg1, "%") && !strstr (arg2, "%"))
425 die (STATE_UNKNOWN,
426 _("%s: Only one threshold must be packet loss (%s)\n"),
427 progname, arg);
430 if (arg2 && strstr (arg2, "%")) {
431 rv[PL] = arg2;
432 rv[RTA] = arg1;
434 else if (arg2) {
435 rv[PL] = arg1;
436 rv[RTA] = arg2;
438 else if (strstr (arg1, "%")) {
439 rv[PL] = arg1;
441 else {
442 rv[RTA] = arg1;
445 return OK;
449 void
450 print_help (void)
453 print_revision (progname, NP_VERSION);
455 printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
456 printf (COPYRIGHT, copyright, email);
458 printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
460 printf ("%s\n", _("Note that it is necessary to set the suid flag on fping."));
462 printf ("\n\n");
464 print_usage ();
466 printf (UT_HELP_VRSN);
467 printf (UT_EXTRA_OPTS);
469 printf (UT_IPv46);
471 printf (" %s\n", "-H, --hostname=HOST");
472 printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
473 printf (" %s\n", "-w, --warning=THRESHOLD");
474 printf (" %s\n", _("warning threshold pair"));
475 printf (" %s\n", "-c, --critical=THRESHOLD");
476 printf (" %s\n", _("critical threshold pair"));
477 printf (" %s\n", "-b, --bytes=INTEGER");
478 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE);
479 printf (" %s\n", "-n, --number=INTEGER");
480 printf (" %s (default: %d)\n", _("number of ICMP packets to send"),PACKET_COUNT);
481 printf (" %s\n", "-T, --target-timeout=INTEGER");
482 printf (" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
483 printf (" %s\n", "-i, --interval=INTEGER");
484 printf (" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
485 printf (" %s\n", "-S, --sourceip=HOST");
486 printf (" %s\n", _("name or IP Address of sourceip"));
487 printf (" %s\n", "-I, --sourceif=IF");
488 printf (" %s\n", _("source interface name"));
489 printf (UT_VERBOSE);
490 printf ("\n");
491 printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
492 printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
493 printf (" %s\n", _("packet loss to trigger an alarm state."));
495 printf ("\n");
496 printf (" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
498 printf (UT_SUPPORT);
502 void
503 print_usage (void)
505 printf ("%s\n", _("Usage:"));
506 printf (" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);