1 /*****************************************************************************
3 * Monitoring check_fping plugin
6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
10 * This file contains the check_disk plugin
12 * This plugin will use the fping command to ping the specified host for a
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-2024";
34 const char *email
= "devel@monitoring-plugins.org";
49 static int textscan(char *buf
);
50 static int process_arguments(int /*argc*/, char ** /*argv*/);
51 static int get_threshold(char *arg
, char *rv
[2]);
52 static void print_help(void);
53 void print_usage(void);
55 static char *server_name
= NULL
;
56 static char *sourceip
= NULL
;
57 static char *sourceif
= NULL
;
58 static int packet_size
= PACKET_SIZE
;
59 static int packet_count
= PACKET_COUNT
;
60 static int target_timeout
= 0;
61 static int packet_interval
= 0;
62 static bool verbose
= false;
67 static bool cpl_p
= false;
68 static bool wpl_p
= false;
69 static bool alive_p
= false;
70 static bool crta_p
= false;
71 static bool wrta_p
= false;
73 int main(int argc
, char **argv
) {
74 /* normally should be int result = STATE_UNKNOWN; */
76 int status
= STATE_UNKNOWN
;
78 char *fping_prog
= 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
);
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 */
99 xasprintf(&option_string
, "%s-t %d ", option_string
, target_timeout
);
101 xasprintf(&option_string
, "%s-p %d ", option_string
, packet_interval
);
103 xasprintf(&option_string
, "%s-S %s ", option_string
, sourceip
);
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
);
111 fping_prog
= strdup(PATH_TO_FPING
);
113 fping_prog
= strdup(PATH_TO_FPING
);
116 xasprintf(&command_line
, "%s %s-b %d -c %d %s", fping_prog
, option_string
, packet_size
, packet_count
, server
);
119 printf("%s\n", command_line
);
121 /* run the command */
122 child_process
= spopen(command_line
);
123 if (child_process
== NULL
) {
124 printf(_("Could not open pipe: %s\n"), command_line
);
125 return STATE_UNKNOWN
;
128 child_stderr
= fdopen(child_stderr_array
[fileno(child_process
)], "r");
129 if (child_stderr
== NULL
) {
130 printf(_("Could not open stderr for %s\n"), command_line
);
133 while (fgets(input_buffer
, MAX_INPUT_BUFFER
- 1, child_process
)) {
135 printf("%s", input_buffer
);
136 status
= max_state(status
, textscan(input_buffer
));
139 /* If we get anything on STDERR, at least set warning */
140 while (fgets(input_buffer
, MAX_INPUT_BUFFER
- 1, child_stderr
)) {
141 status
= max_state(status
, STATE_WARNING
);
143 printf("%s", input_buffer
);
144 status
= max_state(status
, textscan(input_buffer
));
146 (void)fclose(child_stderr
);
149 result
= spclose(child_process
);
151 /* need to use max_state not max */
152 status
= max_state(status
, STATE_WARNING
);
156 status
= max_state(status
, STATE_UNKNOWN
);
158 die(STATE_UNKNOWN
, _("FPING UNKNOWN - IP address not found\n"));
161 die(STATE_UNKNOWN
, _("FPING UNKNOWN - invalid commandline argument\n"));
164 die(STATE_UNKNOWN
, _("FPING UNKNOWN - failed system call\n"));
168 printf("FPING %s - %s\n", state_text(status
), server_name
);
173 int textscan(char *buf
) {
180 int status
= STATE_UNKNOWN
;
182 /* stops testing after the first successful reply. */
183 if (alive_p
&& strstr(buf
, "avg, 0% loss)")) {
184 rtastr
= strstr(buf
, "ms (");
185 rtastr
= 1 + index(rtastr
, '(');
186 rta
= strtod(rtastr
, NULL
);
187 loss
= strtod("0", NULL
);
188 die(STATE_OK
, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK
), server_name
, rta
,
189 /* No loss since we only waited for the first reply
190 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
191 fperfdata("rta", rta
/ 1.0e3
, "s", wrta_p
, wrta
/ 1.0e3
, crta_p
, crta
/ 1.0e3
, true, 0, false, 0));
194 if (strstr(buf
, "not found")) {
195 die(STATE_CRITICAL
, _("FPING UNKNOWN - %s not found\n"), server_name
);
197 } else if (strstr(buf
, "is unreachable") || strstr(buf
, "Unreachable")) {
198 die(STATE_CRITICAL
, _("FPING CRITICAL - %s is unreachable\n"), "host");
200 } else if (strstr(buf
, "Operation not permitted") || strstr(buf
, "No such device")) {
201 die(STATE_UNKNOWN
, _("FPING UNKNOWN - %s parameter error\n"), "host");
202 } else if (strstr(buf
, "is down")) {
203 die(STATE_CRITICAL
, _("FPING CRITICAL - %s is down\n"), server_name
);
205 } else if (strstr(buf
, "is alive")) {
208 } else if (strstr(buf
, "xmt/rcv/%loss") && strstr(buf
, "min/avg/max")) {
209 losstr
= strstr(buf
, "=");
210 losstr
= 1 + strstr(losstr
, "/");
211 losstr
= 1 + strstr(losstr
, "/");
212 rtastr
= strstr(buf
, "min/avg/max");
213 rtastr
= strstr(rtastr
, "=");
214 rtastr
= 1 + index(rtastr
, '/');
215 loss
= strtod(losstr
, NULL
);
216 rta
= strtod(rtastr
, NULL
);
217 if (cpl_p
&& loss
> cpl
)
218 status
= STATE_CRITICAL
;
219 else if (crta_p
&& rta
> crta
)
220 status
= STATE_CRITICAL
;
221 else if (wpl_p
&& loss
> wpl
)
222 status
= STATE_WARNING
;
223 else if (wrta_p
&& rta
> wrta
)
224 status
= STATE_WARNING
;
227 die(status
, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status
), server_name
, loss
, rta
,
228 perfdata("loss", (long int)loss
, "%", wpl_p
, wpl
, cpl_p
, cpl
, true, 0, true, 100),
229 fperfdata("rta", rta
/ 1.0e3
, "s", wrta_p
, wrta
/ 1.0e3
, crta_p
, crta
/ 1.0e3
, true, 0, false, 0));
231 } else if (strstr(buf
, "xmt/rcv/%loss")) {
232 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
233 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
234 losstr
= strstr(buf
, "=");
236 xmt
= strtod(xmtstr
, NULL
);
238 die(STATE_CRITICAL
, _("FPING CRITICAL - %s is down\n"), server_name
);
239 losstr
= 1 + strstr(losstr
, "/");
240 losstr
= 1 + strstr(losstr
, "/");
241 loss
= strtod(losstr
, NULL
);
242 if (atoi(losstr
) == 100)
243 status
= STATE_CRITICAL
;
244 else if (cpl_p
&& loss
> cpl
)
245 status
= STATE_CRITICAL
;
246 else if (wpl_p
&& loss
> wpl
)
247 status
= STATE_WARNING
;
250 /* loss=%.0f%%;%d;%d;0;100 */
251 die(status
, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status
), server_name
, loss
,
252 perfdata("loss", (long int)loss
, "%", wpl_p
, wpl
, cpl_p
, cpl
, true, 0, true, 100));
255 status
= max_state(status
, STATE_WARNING
);
261 /* process command-line arguments */
262 int process_arguments(int argc
, char **argv
) {
267 static struct option longopts
[] = {{"hostname", required_argument
, 0, 'H'},
268 {"sourceip", required_argument
, 0, 'S'},
269 {"sourceif", required_argument
, 0, 'I'},
270 {"critical", required_argument
, 0, 'c'},
271 {"warning", required_argument
, 0, 'w'},
272 {"alive", no_argument
, 0, 'a'},
273 {"bytes", required_argument
, 0, 'b'},
274 {"number", required_argument
, 0, 'n'},
275 {"target-timeout", required_argument
, 0, 'T'},
276 {"interval", required_argument
, 0, 'i'},
277 {"verbose", no_argument
, 0, 'v'},
278 {"version", no_argument
, 0, 'V'},
279 {"help", no_argument
, 0, 'h'},
280 {"use-ipv4", no_argument
, 0, '4'},
281 {"use-ipv6", no_argument
, 0, '6'},
290 if (!is_option(argv
[1])) {
291 server_name
= argv
[1];
298 c
= getopt_long(argc
, argv
, "+hVvaH:S:c:w:b:n:T:i:I:46", longopts
, &option
);
300 if (c
== -1 || c
== EOF
|| c
== 1)
304 case '?': /* print short usage statement if args not parsable */
306 case 'a': /* host alive mode */
312 case 'V': /* version */
313 print_revision(progname
, NP_VERSION
);
315 case 'v': /* verbose mode */
318 case 'H': /* hostname */
319 if (is_host(optarg
) == false) {
320 usage2(_("Invalid hostname/address"), optarg
);
322 server_name
= strscpy(server_name
, optarg
);
324 case 'S': /* sourceip */
325 if (is_host(optarg
) == false) {
326 usage2(_("Invalid hostname/address"), optarg
);
328 sourceip
= strscpy(sourceip
, optarg
);
330 case 'I': /* sourceip */
331 sourceif
= strscpy(sourceif
, optarg
);
333 case '4': /* IPv4 only */
334 address_family
= AF_INET
;
336 case '6': /* IPv6 only */
338 address_family
= AF_INET6
;
340 usage(_("IPv6 support not available\n"));
344 get_threshold(optarg
, rv
);
346 crta
= strtod(rv
[RTA
], NULL
);
357 get_threshold(optarg
, rv
);
359 wrta
= strtod(rv
[RTA
], NULL
);
369 case 'b': /* bytes per packet */
370 if (is_intpos(optarg
))
371 packet_size
= atoi(optarg
);
373 usage(_("Packet size must be a positive integer"));
375 case 'n': /* number of packets */
376 if (is_intpos(optarg
))
377 packet_count
= atoi(optarg
);
379 usage(_("Packet count must be a positive integer"));
381 case 'T': /* timeout in msec */
382 if (is_intpos(optarg
))
383 target_timeout
= atoi(optarg
);
385 usage(_("Target timeout must be a positive integer"));
387 case 'i': /* interval in msec */
388 if (is_intpos(optarg
))
389 packet_interval
= atoi(optarg
);
391 usage(_("Interval must be a positive integer"));
396 if (server_name
== NULL
)
397 usage4(_("Hostname was not supplied"));
402 int get_threshold(char *arg
, char *rv
[2]) {
406 arg1
= strscpy(arg1
, arg
);
407 if (strpbrk(arg1
, ",:"))
408 arg2
= 1 + strpbrk(arg1
, ",:");
411 arg1
[strcspn(arg1
, ",:")] = 0;
412 if (strstr(arg1
, "%") && strstr(arg2
, "%"))
413 die(STATE_UNKNOWN
, _("%s: Only one threshold may be packet loss (%s)\n"), progname
, arg
);
414 if (!strstr(arg1
, "%") && !strstr(arg2
, "%"))
415 die(STATE_UNKNOWN
, _("%s: Only one threshold must be packet loss (%s)\n"), progname
, arg
);
418 if (arg2
&& strstr(arg2
, "%")) {
424 } else if (strstr(arg1
, "%")) {
433 void print_help(void) {
435 print_revision(progname
, NP_VERSION
);
437 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
438 printf(COPYRIGHT
, copyright
, email
);
440 printf("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
442 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
448 printf(UT_HELP_VRSN
);
449 printf(UT_EXTRA_OPTS
);
453 printf(" %s\n", "-H, --hostname=HOST");
454 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
455 printf(" %s\n", "-w, --warning=THRESHOLD");
456 printf(" %s\n", _("warning threshold pair"));
457 printf(" %s\n", "-c, --critical=THRESHOLD");
458 printf(" %s\n", _("critical threshold pair"));
459 printf(" %s\n", "-a, --alive");
460 printf(" %s\n", _("Return OK after first successful reply"));
461 printf(" %s\n", "-b, --bytes=INTEGER");
462 printf(" %s (default: %d)\n", _("size of ICMP packet"), PACKET_SIZE
);
463 printf(" %s\n", "-n, --number=INTEGER");
464 printf(" %s (default: %d)\n", _("number of ICMP packets to send"), PACKET_COUNT
);
465 printf(" %s\n", "-T, --target-timeout=INTEGER");
466 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
467 printf(" %s\n", "-i, --interval=INTEGER");
468 printf(" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
469 printf(" %s\n", "-S, --sourceip=HOST");
470 printf(" %s\n", _("name or IP Address of sourceip"));
471 printf(" %s\n", "-I, --sourceif=IF");
472 printf(" %s\n", _("source interface name"));
475 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
476 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
477 printf(" %s\n", _("packet loss to trigger an alarm state."));
480 printf(" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
485 void print_usage(void) {
486 printf("%s\n", _("Usage:"));
487 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname
);