1 /*****************************************************************************
3 * Monitoring check_fping plugin
6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
10 * This file contains the check_fping 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;
63 static bool dontfrag
= false;
64 static bool randomize_packet_data
= false;
69 static bool cpl_p
= false;
70 static bool wpl_p
= false;
71 static bool alive_p
= false;
72 static bool crta_p
= false;
73 static bool wrta_p
= false;
75 int main(int argc
, char **argv
) {
76 /* normally should be int result = STATE_UNKNOWN; */
78 int status
= STATE_UNKNOWN
;
80 char *fping_prog
= NULL
;
82 char *command_line
= NULL
;
83 char *input_buffer
= NULL
;
84 char *option_string
= "";
85 input_buffer
= malloc(MAX_INPUT_BUFFER
);
87 setlocale(LC_ALL
, "");
88 bindtextdomain(PACKAGE
, LOCALEDIR
);
91 /* Parse extra opts if any */
92 argv
= np_extra_opts(&argc
, argv
, progname
);
94 if (process_arguments(argc
, argv
) == ERROR
)
95 usage4(_("Could not parse arguments"));
97 server
= strscpy(server
, server_name
);
99 /* compose the command */
101 xasprintf(&option_string
, "%s-t %d ", option_string
, target_timeout
);
103 xasprintf(&option_string
, "%s-p %d ", option_string
, packet_interval
);
105 xasprintf(&option_string
, "%s-S %s ", option_string
, sourceip
);
107 xasprintf(&option_string
, "%s-I %s ", option_string
, sourceif
);
109 xasprintf(&option_string
, "%s-M ", option_string
);
110 if (randomize_packet_data
)
111 xasprintf(&option_string
, "%s-R ", option_string
);
114 #ifdef PATH_TO_FPING6
115 if (address_family
!= AF_INET
&& is_inet6_addr(server
))
116 fping_prog
= strdup(PATH_TO_FPING6
);
118 fping_prog
= strdup(PATH_TO_FPING
);
120 fping_prog
= strdup(PATH_TO_FPING
);
123 xasprintf(&command_line
, "%s %s-b %d -c %d %s", fping_prog
, option_string
, packet_size
, packet_count
, server
);
126 printf("%s\n", command_line
);
128 /* run the command */
129 child_process
= spopen(command_line
);
130 if (child_process
== NULL
) {
131 printf(_("Could not open pipe: %s\n"), command_line
);
132 return STATE_UNKNOWN
;
135 child_stderr
= fdopen(child_stderr_array
[fileno(child_process
)], "r");
136 if (child_stderr
== NULL
) {
137 printf(_("Could not open stderr for %s\n"), command_line
);
140 while (fgets(input_buffer
, MAX_INPUT_BUFFER
- 1, child_process
)) {
142 printf("%s", input_buffer
);
143 status
= max_state(status
, textscan(input_buffer
));
146 /* If we get anything on STDERR, at least set warning */
147 while (fgets(input_buffer
, MAX_INPUT_BUFFER
- 1, child_stderr
)) {
148 status
= max_state(status
, STATE_WARNING
);
150 printf("%s", input_buffer
);
151 status
= max_state(status
, textscan(input_buffer
));
153 (void)fclose(child_stderr
);
156 result
= spclose(child_process
);
158 /* need to use max_state not max */
159 status
= max_state(status
, STATE_WARNING
);
163 status
= max_state(status
, STATE_UNKNOWN
);
165 die(STATE_UNKNOWN
, _("FPING UNKNOWN - IP address not found\n"));
168 die(STATE_UNKNOWN
, _("FPING UNKNOWN - invalid commandline argument\n"));
171 die(STATE_UNKNOWN
, _("FPING UNKNOWN - failed system call\n"));
175 printf("FPING %s - %s\n", state_text(status
), server_name
);
180 int textscan(char *buf
) {
187 int status
= STATE_UNKNOWN
;
189 /* stops testing after the first successful reply. */
190 if (alive_p
&& strstr(buf
, "avg, 0% loss)")) {
191 rtastr
= strstr(buf
, "ms (");
192 rtastr
= 1 + index(rtastr
, '(');
193 rta
= strtod(rtastr
, NULL
);
194 loss
= strtod("0", NULL
);
195 die(STATE_OK
, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK
), server_name
, rta
,
196 /* No loss since we only waited for the first reply
197 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
198 fperfdata("rta", rta
/ 1.0e3
, "s", wrta_p
, wrta
/ 1.0e3
, crta_p
, crta
/ 1.0e3
, true, 0, false, 0));
201 if (strstr(buf
, "not found")) {
202 die(STATE_CRITICAL
, _("FPING UNKNOWN - %s not found\n"), server_name
);
204 } else if (strstr(buf
, "is unreachable") || strstr(buf
, "Unreachable")) {
205 die(STATE_CRITICAL
, _("FPING CRITICAL - %s is unreachable\n"), "host");
207 } else if (strstr(buf
, "Operation not permitted") || strstr(buf
, "No such device")) {
208 die(STATE_UNKNOWN
, _("FPING UNKNOWN - %s parameter error\n"), "host");
209 } else if (strstr(buf
, "is down")) {
210 die(STATE_CRITICAL
, _("FPING CRITICAL - %s is down\n"), server_name
);
212 } else if (strstr(buf
, "is alive")) {
215 } else if (strstr(buf
, "xmt/rcv/%loss") && strstr(buf
, "min/avg/max")) {
216 losstr
= strstr(buf
, "=");
217 losstr
= 1 + strstr(losstr
, "/");
218 losstr
= 1 + strstr(losstr
, "/");
219 rtastr
= strstr(buf
, "min/avg/max");
220 rtastr
= strstr(rtastr
, "=");
221 rtastr
= 1 + index(rtastr
, '/');
222 loss
= strtod(losstr
, NULL
);
223 rta
= strtod(rtastr
, NULL
);
224 if (cpl_p
&& loss
> cpl
)
225 status
= STATE_CRITICAL
;
226 else if (crta_p
&& rta
> crta
)
227 status
= STATE_CRITICAL
;
228 else if (wpl_p
&& loss
> wpl
)
229 status
= STATE_WARNING
;
230 else if (wrta_p
&& rta
> wrta
)
231 status
= STATE_WARNING
;
234 die(status
, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status
), server_name
, loss
, rta
,
235 perfdata("loss", (long int)loss
, "%", wpl_p
, wpl
, cpl_p
, cpl
, true, 0, true, 100),
236 fperfdata("rta", rta
/ 1.0e3
, "s", wrta_p
, wrta
/ 1.0e3
, crta_p
, crta
/ 1.0e3
, true, 0, false, 0));
238 } else if (strstr(buf
, "xmt/rcv/%loss")) {
239 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
240 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
241 losstr
= strstr(buf
, "=");
243 xmt
= strtod(xmtstr
, NULL
);
245 die(STATE_CRITICAL
, _("FPING CRITICAL - %s is down\n"), server_name
);
246 losstr
= 1 + strstr(losstr
, "/");
247 losstr
= 1 + strstr(losstr
, "/");
248 loss
= strtod(losstr
, NULL
);
249 if (atoi(losstr
) == 100)
250 status
= STATE_CRITICAL
;
251 else if (cpl_p
&& loss
> cpl
)
252 status
= STATE_CRITICAL
;
253 else if (wpl_p
&& loss
> wpl
)
254 status
= STATE_WARNING
;
257 /* loss=%.0f%%;%d;%d;0;100 */
258 die(status
, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status
), server_name
, loss
,
259 perfdata("loss", (long int)loss
, "%", wpl_p
, wpl
, cpl_p
, cpl
, true, 0, true, 100));
262 status
= max_state(status
, STATE_WARNING
);
268 /* process command-line arguments */
269 int process_arguments(int argc
, char **argv
) {
274 static struct option longopts
[] = {{"hostname", required_argument
, 0, 'H'},
275 {"sourceip", required_argument
, 0, 'S'},
276 {"sourceif", required_argument
, 0, 'I'},
277 {"critical", required_argument
, 0, 'c'},
278 {"warning", required_argument
, 0, 'w'},
279 {"alive", no_argument
, 0, 'a'},
280 {"bytes", required_argument
, 0, 'b'},
281 {"number", required_argument
, 0, 'n'},
282 {"target-timeout", required_argument
, 0, 'T'},
283 {"interval", required_argument
, 0, 'i'},
284 {"verbose", no_argument
, 0, 'v'},
285 {"version", no_argument
, 0, 'V'},
286 {"help", no_argument
, 0, 'h'},
287 {"use-ipv4", no_argument
, 0, '4'},
288 {"use-ipv6", no_argument
, 0, '6'},
289 {"dontfrag", no_argument
, 0, 'M'},
290 {"random", no_argument
, 0, 'R'},
299 if (!is_option(argv
[1])) {
300 server_name
= argv
[1];
307 c
= getopt_long(argc
, argv
, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts
, &option
);
309 if (c
== -1 || c
== EOF
|| c
== 1)
313 case '?': /* print short usage statement if args not parsable */
315 case 'a': /* host alive mode */
321 case 'V': /* version */
322 print_revision(progname
, NP_VERSION
);
324 case 'v': /* verbose mode */
327 case 'H': /* hostname */
328 if (is_host(optarg
) == false) {
329 usage2(_("Invalid hostname/address"), optarg
);
331 server_name
= strscpy(server_name
, optarg
);
333 case 'S': /* sourceip */
334 if (is_host(optarg
) == false) {
335 usage2(_("Invalid hostname/address"), optarg
);
337 sourceip
= strscpy(sourceip
, optarg
);
339 case 'I': /* sourceip */
340 sourceif
= strscpy(sourceif
, optarg
);
342 case '4': /* IPv4 only */
343 address_family
= AF_INET
;
345 case '6': /* IPv6 only */
347 address_family
= AF_INET6
;
349 usage(_("IPv6 support not available\n"));
353 get_threshold(optarg
, rv
);
355 crta
= strtod(rv
[RTA
], NULL
);
366 get_threshold(optarg
, rv
);
368 wrta
= strtod(rv
[RTA
], NULL
);
378 case 'b': /* bytes per packet */
379 if (is_intpos(optarg
))
380 packet_size
= atoi(optarg
);
382 usage(_("Packet size must be a positive integer"));
384 case 'n': /* number of packets */
385 if (is_intpos(optarg
))
386 packet_count
= atoi(optarg
);
388 usage(_("Packet count must be a positive integer"));
390 case 'T': /* timeout in msec */
391 if (is_intpos(optarg
))
392 target_timeout
= atoi(optarg
);
394 usage(_("Target timeout must be a positive integer"));
396 case 'i': /* interval in msec */
397 if (is_intpos(optarg
))
398 packet_interval
= atoi(optarg
);
400 usage(_("Interval must be a positive integer"));
403 randomize_packet_data
= true;
411 if (server_name
== NULL
)
412 usage4(_("Hostname was not supplied"));
417 int get_threshold(char *arg
, char *rv
[2]) {
421 arg1
= strscpy(arg1
, arg
);
422 if (strpbrk(arg1
, ",:"))
423 arg2
= 1 + strpbrk(arg1
, ",:");
426 arg1
[strcspn(arg1
, ",:")] = 0;
427 if (strstr(arg1
, "%") && strstr(arg2
, "%"))
428 die(STATE_UNKNOWN
, _("%s: Only one threshold may be packet loss (%s)\n"), progname
, arg
);
429 if (!strstr(arg1
, "%") && !strstr(arg2
, "%"))
430 die(STATE_UNKNOWN
, _("%s: Only one threshold must be packet loss (%s)\n"), progname
, arg
);
433 if (arg2
&& strstr(arg2
, "%")) {
439 } else if (strstr(arg1
, "%")) {
448 void print_help(void) {
450 print_revision(progname
, NP_VERSION
);
452 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
453 printf(COPYRIGHT
, copyright
, email
);
455 printf("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
457 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
463 printf(UT_HELP_VRSN
);
464 printf(UT_EXTRA_OPTS
);
468 printf(" %s\n", "-H, --hostname=HOST");
469 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
470 printf(" %s\n", "-w, --warning=THRESHOLD");
471 printf(" %s\n", _("warning threshold pair"));
472 printf(" %s\n", "-c, --critical=THRESHOLD");
473 printf(" %s\n", _("critical threshold pair"));
474 printf(" %s\n", "-a, --alive");
475 printf(" %s\n", _("Return OK after first successful reply"));
476 printf(" %s\n", "-b, --bytes=INTEGER");
477 printf(" %s (default: %d)\n", _("size of ICMP packet"), PACKET_SIZE
);
478 printf(" %s\n", "-n, --number=INTEGER");
479 printf(" %s (default: %d)\n", _("number of ICMP packets to send"), PACKET_COUNT
);
480 printf(" %s\n", "-T, --target-timeout=INTEGER");
481 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
482 printf(" %s\n", "-i, --interval=INTEGER");
483 printf(" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
484 printf(" %s\n", "-S, --sourceip=HOST");
485 printf(" %s\n", _("name or IP Address of sourceip"));
486 printf(" %s\n", "-I, --sourceif=IF");
487 printf(" %s\n", _("source interface name"));
488 printf(" %s\n", "-M, --dontfrag");
489 printf(" %s\n", _("set the Don't Fragment flag"));
490 printf(" %s\n", "-R, --random");
491 printf(" %s\n", _("random packet data (to foil link data compression)"));
494 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
495 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
496 printf(" %s\n", _("packet loss to trigger an alarm state."));
499 printf(" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
504 void 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
);