summaryrefslogtreecommitdiffstats
path: root/plugins/check_fping.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_fping.c')
-rw-r--r--plugins/check_fping.c1034
1 files changed, 544 insertions, 490 deletions
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index 70d6f9fc..8018e06d 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_fping plugin 3 * Monitoring check_fping plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_disk plugin 10 * This file contains the check_fping plugin
11* 11 *
12* This plugin will use the fping command to ping the specified host for a 12 * This plugin will use the fping command to ping the specified host for a
13* fast check 13 * fast check
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_fping"; 32const char *progname = "check_fping";
33const char *copyright = "2000-2007"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
@@ -38,490 +38,544 @@ const char *email = "devel@monitoring-plugins.org";
38#include "netutils.h" 38#include "netutils.h"
39#include "utils.h" 39#include "utils.h"
40#include <stdbool.h> 40#include <stdbool.h>
41#include "check_fping.d/config.h"
42#include "states.h"
41 43
42enum { 44enum {
43 PACKET_COUNT = 1, 45 PL = 0,
44 PACKET_SIZE = 56, 46 RTA = 1
45 PL = 0,
46 RTA = 1
47}; 47};
48 48
49int textscan (char *buf); 49static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/, double /*crta*/, bool /*wrta_p*/, double /*wrta*/,
50int process_arguments (int, char **); 50 bool /*cpl_p*/, int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
51int get_threshold (char *arg, char *rv[2]); 51
52void print_help (void); 52typedef struct {
53void print_usage (void); 53 int errorcode;
54 54 check_fping_config config;
55char *server_name = NULL; 55} check_fping_config_wrapper;
56char *sourceip = NULL; 56static check_fping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57char *sourceif = NULL; 57static int get_threshold(char *arg, char *rv[2]);
58int packet_size = PACKET_SIZE; 58static void print_help(void);
59int packet_count = PACKET_COUNT; 59void print_usage(void);
60int target_timeout = 0; 60
61int packet_interval = 0; 61static bool verbose = false;
62bool verbose = false; 62
63int cpl; 63int main(int argc, char **argv) {
64int wpl; 64 setlocale(LC_ALL, "");
65double crta; 65 bindtextdomain(PACKAGE, LOCALEDIR);
66double wrta; 66 textdomain(PACKAGE);
67bool cpl_p = false; 67
68bool wpl_p = false; 68 /* Parse extra opts if any */
69bool alive_p = false; 69 argv = np_extra_opts(&argc, argv, progname);
70bool crta_p = false; 70
71bool wrta_p = false; 71 check_fping_config_wrapper tmp_config = process_arguments(argc, argv);
72 72 if (tmp_config.errorcode == ERROR) {
73int 73 usage4(_("Could not parse arguments"));
74main (int argc, char **argv) 74 }
75{ 75
76/* normally should be int result = STATE_UNKNOWN; */ 76 const check_fping_config config = tmp_config.config;
77 77
78 int status = STATE_UNKNOWN; 78 char *server = NULL;
79 int result = 0; 79 server = strscpy(server, config.server_name);
80 char *fping_prog = NULL; 80
81 char *server = NULL; 81 char *option_string = "";
82 char *command_line = NULL; 82 char *fping_prog = NULL;
83 char *input_buffer = NULL; 83
84 char *option_string = ""; 84 /* First determine if the target is dualstack or ipv6 only. */
85 input_buffer = malloc (MAX_INPUT_BUFFER); 85 bool server_is_inet6_addr = is_inet6_addr(server);
86 86
87 setlocale (LC_ALL, ""); 87 /*
88 bindtextdomain (PACKAGE, LOCALEDIR); 88 * If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
89 textdomain (PACKAGE); 89 * -> we use ipv6
90 90 * If the user requested -4 OR the user made no assertion and the address is v4 ONLY
91 /* Parse extra opts if any */ 91 * -> we use ipv4
92 argv=np_extra_opts (&argc, argv, progname); 92 */
93 93 if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
94 if (process_arguments (argc, argv) == ERROR) 94 xasprintf(&option_string, "%s-6 ", option_string);
95 usage4 (_("Could not parse arguments")); 95 } else {
96 96 xasprintf(&option_string, "%s-4 ", option_string);
97 server = strscpy (server, server_name); 97 }
98 98 fping_prog = strdup(PATH_TO_FPING);
99 /* compose the command */ 99
100 if (target_timeout) 100 /* compose the command */
101 xasprintf(&option_string, "%s-t %d ", option_string, target_timeout); 101 if (config.target_timeout) {
102 if (packet_interval) 102 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
103 xasprintf(&option_string, "%s-p %d ", option_string, packet_interval); 103 }
104 if (sourceip) 104 if (config.packet_interval) {
105 xasprintf(&option_string, "%s-S %s ", option_string, sourceip); 105 xasprintf(&option_string, "%s-p %d ", option_string, config.packet_interval);
106 if (sourceif) 106 }
107 xasprintf(&option_string, "%s-I %s ", option_string, sourceif); 107 if (config.sourceip) {
108 108 xasprintf(&option_string, "%s-S %s ", option_string, config.sourceip);
109#ifdef PATH_TO_FPING6 109 }
110 if (address_family != AF_INET && is_inet6_addr(server)) 110 if (config.sourceif) {
111 fping_prog = strdup(PATH_TO_FPING6); 111 xasprintf(&option_string, "%s-I %s ", option_string, config.sourceif);
112 else 112 }
113 fping_prog = strdup(PATH_TO_FPING); 113 if (config.dontfrag) {
114#else 114 xasprintf(&option_string, "%s-M ", option_string);
115 fping_prog = strdup(PATH_TO_FPING); 115 }
116#endif 116 if (config.randomize_packet_data) {
117 117 xasprintf(&option_string, "%s-R ", option_string);
118 xasprintf (&command_line, "%s %s-b %d -c %d %s", fping_prog, 118 }
119 option_string, packet_size, packet_count, server); 119
120 120 if (config.fwmark_set) {
121 if (verbose) 121 xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
122 printf ("%s\n", command_line); 122 }
123 123
124 /* run the command */ 124 if (config.icmp_timestamp) {
125 child_process = spopen (command_line); 125 xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
126 if (child_process == NULL) { 126 }
127 printf (_("Could not open pipe: %s\n"), command_line); 127
128 return STATE_UNKNOWN; 128 if (config.check_source) {
129 } 129 xasprintf(&option_string, "%s--check-source ", option_string);
130 130 }
131 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 131
132 if (child_stderr == NULL) { 132 char *command_line = NULL;
133 printf (_("Could not open stderr for %s\n"), command_line); 133
134 } 134 if (config.icmp_timestamp) {
135 135 // no packet size settable for ICMP timestamp
136 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 136 xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count, server);
137 if (verbose) 137 } else {
138 printf ("%s", input_buffer); 138 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
139 status = max_state (status, textscan (input_buffer)); 139 }
140 } 140
141 141 if (verbose) {
142 /* If we get anything on STDERR, at least set warning */ 142 printf("%s\n", command_line);
143 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 143 }
144 status = max_state (status, STATE_WARNING); 144
145 if (verbose) 145 /* run the command */
146 printf ("%s", input_buffer); 146 child_process = spopen(command_line);
147 status = max_state (status, textscan (input_buffer)); 147 if (child_process == NULL) {
148 } 148 printf(_("Could not open pipe: %s\n"), command_line);
149 (void) fclose (child_stderr); 149 return STATE_UNKNOWN;
150 150 }
151 /* close the pipe */ 151
152 result = spclose (child_process); 152 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
153 if (result) { 153 if (child_stderr == NULL) {
154 /* need to use max_state not max */ 154 printf(_("Could not open stderr for %s\n"), command_line);
155 status = max_state (status, STATE_WARNING); 155 }
156 } 156
157 157 char *input_buffer = malloc(MAX_INPUT_BUFFER);
158 if (result > 1 ) { 158 mp_state_enum status = STATE_UNKNOWN;
159 status = max_state (status, STATE_UNKNOWN); 159 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
160 if (result == 2) { 160 if (verbose) {
161 die (STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n")); 161 printf("%s", input_buffer);
162 } 162 }
163 if (result == 3) { 163 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
164 die (STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n")); 164 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
165 } 165 }
166 if (result == 4) { 166
167 die (STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n")); 167 /* If we get anything on STDERR, at least set warning */
168 } 168 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
169 169 status = max_state(status, STATE_WARNING);
170 } 170 if (verbose) {
171 171 printf("%s", input_buffer);
172 printf ("FPING %s - %s\n", state_text (status), server_name); 172 }
173 173 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
174 return status; 174 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
175 }
176 (void)fclose(child_stderr);
177
178 /* close the pipe */
179 int result = spclose(child_process);
180 if (result) {
181 /* need to use max_state not max */
182 status = max_state(status, STATE_WARNING);
183 }
184
185 if (result > 1) {
186 status = max_state(status, STATE_UNKNOWN);
187 if (result == 2) {
188 die(STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n"));
189 }
190 if (result == 3) {
191 die(STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n"));
192 }
193 if (result == 4) {
194 die(STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n"));
195 }
196 }
197
198 printf("FPING %s - %s\n", state_text(status), config.server_name);
199
200 return status;
175} 201}
176 202
177 203mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p, double wrta, bool cpl_p, int cpl,
178int textscan (char *buf) { 204 bool wpl_p, int wpl, bool alive_p) {
179 char *rtastr = NULL; 205 /* stops testing after the first successful reply. */
180 char *losstr = NULL; 206 double rta;
181 char *xmtstr = NULL; 207 double loss;
182 double loss; 208 char *rtastr = NULL;
183 double rta; 209 if (alive_p && strstr(buf, "avg, 0% loss)")) {
184 double xmt; 210 rtastr = strstr(buf, "ms (");
185 int status = STATE_UNKNOWN; 211 rtastr = 1 + index(rtastr, '(');
186 212 rta = strtod(rtastr, NULL);
187 /* stops testing after the first successful reply. */ 213 loss = strtod("0", NULL);
188 if (alive_p && strstr(buf, "avg, 0% loss)")) { 214 die(STATE_OK, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK), server_name, rta,
189 rtastr = strstr (buf, "ms ("); 215 /* No loss since we only waited for the first reply
190 rtastr = 1 + index(rtastr, '('); 216 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
191 rta = strtod(rtastr, NULL); 217 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
192 loss=strtod("0",NULL); 218 }
193 die (STATE_OK, 219
194 _("FPING %s - %s (rta=%f ms)|%s\n"), 220 mp_state_enum status = STATE_UNKNOWN;
195 state_text (STATE_OK), server_name,rta, 221 char *xmtstr = NULL;
196 /* No loss since we only waited for the first reply 222 double xmt;
197 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */ 223 char *losstr = NULL;
198 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 224 if (strstr(buf, "not found")) {
199 } 225 die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
200 226
201 if (strstr (buf, "not found")) { 227 } else if (strstr(buf, "is unreachable") || strstr(buf, "Unreachable")) {
202 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name); 228 die(STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), "host");
203 229
204 } 230 } else if (strstr(buf, "Operation not permitted") || strstr(buf, "No such device")) {
205 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) { 231 die(STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), "host");
206 die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), 232 } else if (strstr(buf, "is down")) {
207 "host"); 233 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
208 234
209 } 235 } else if (strstr(buf, "is alive")) {
210 else if (strstr (buf, "Operation not permitted") || strstr (buf, "No such device") ) { 236 status = STATE_OK;
211 die (STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), 237
212 "host"); 238 } else if (strstr(buf, "xmt/rcv/%loss") && strstr(buf, "min/avg/max")) {
213 } 239 losstr = strstr(buf, "=");
214 else if (strstr (buf, "is down")) { 240 losstr = 1 + strstr(losstr, "/");
215 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 241 losstr = 1 + strstr(losstr, "/");
216 242 rtastr = strstr(buf, "min/avg/max");
217 } 243 rtastr = strstr(rtastr, "=");
218 else if (strstr (buf, "is alive")) { 244 rtastr = 1 + index(rtastr, '/');
219 status = STATE_OK; 245 loss = strtod(losstr, NULL);
220 246 rta = strtod(rtastr, NULL);
221 } 247 if (cpl_p && loss > cpl) {
222 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) { 248 status = STATE_CRITICAL;
223 losstr = strstr (buf, "="); 249 } else if (crta_p && rta > crta) {
224 losstr = 1 + strstr (losstr, "/"); 250 status = STATE_CRITICAL;
225 losstr = 1 + strstr (losstr, "/"); 251 } else if (wpl_p && loss > wpl) {
226 rtastr = strstr (buf, "min/avg/max"); 252 status = STATE_WARNING;
227 rtastr = strstr (rtastr, "="); 253 } else if (wrta_p && rta > wrta) {
228 rtastr = 1 + index (rtastr, '/'); 254 status = STATE_WARNING;
229 loss = strtod (losstr, NULL); 255 } else {
230 rta = strtod (rtastr, NULL); 256 status = STATE_OK;
231 if (cpl_p && loss > cpl) 257 }
232 status = STATE_CRITICAL; 258 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta,
233 else if (crta_p && rta > crta) 259 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
234 status = STATE_CRITICAL; 260 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
235 else if (wpl_p && loss > wpl) 261
236 status = STATE_WARNING; 262 } else if (strstr(buf, "xmt/rcv/%loss")) {
237 else if (wrta_p && rta > wrta) 263 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
238 status = STATE_WARNING; 264 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
239 else 265 losstr = strstr(buf, "=");
240 status = STATE_OK; 266 xmtstr = 1 + losstr;
241 die (status, 267 xmt = strtod(xmtstr, NULL);
242 _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), 268 if (xmt == 0) {
243 state_text (status), server_name, loss, rta, 269 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
244 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), 270 }
245 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 271 losstr = 1 + strstr(losstr, "/");
246 272 losstr = 1 + strstr(losstr, "/");
247 } 273 loss = strtod(losstr, NULL);
248 else if(strstr (buf, "xmt/rcv/%loss") ) { 274 if (atoi(losstr) == 100) {
249 /* no min/max/avg if host was unreachable in fping v2.2.b1 */ 275 status = STATE_CRITICAL;
250 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */ 276 } else if (cpl_p && loss > cpl) {
251 losstr = strstr (buf, "="); 277 status = STATE_CRITICAL;
252 xmtstr = 1 + losstr; 278 } else if (wpl_p && loss > wpl) {
253 xmt = strtod (xmtstr, NULL); 279 status = STATE_WARNING;
254 if(xmt == 0) 280 } else {
255 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 281 status = STATE_OK;
256 losstr = 1 + strstr (losstr, "/"); 282 }
257 losstr = 1 + strstr (losstr, "/"); 283 /* loss=%.0f%%;%d;%d;0;100 */
258 loss = strtod (losstr, NULL); 284 die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss,
259 if (atoi(losstr) == 100) 285 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0));
260 status = STATE_CRITICAL; 286
261 else if (cpl_p && loss > cpl) 287 } else {
262 status = STATE_CRITICAL; 288 status = max_state(status, STATE_WARNING);
263 else if (wpl_p && loss > wpl) 289 }
264 status = STATE_WARNING; 290
265 else 291 return status;
266 status = STATE_OK;
267 /* loss=%.0f%%;%d;%d;0;100 */
268 die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"),
269 state_text (status), server_name, loss ,
270 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100));
271
272 }
273 else {
274 status = max_state (status, STATE_WARNING);
275 }
276
277 return status;
278} 292}
279 293
280
281
282/* process command-line arguments */ 294/* process command-line arguments */
283int 295check_fping_config_wrapper process_arguments(int argc, char **argv) {
284process_arguments (int argc, char **argv) 296 enum {
285{ 297 FWMARK_OPT = CHAR_MAX + 1,
286 int c; 298 ICMP_TIMESTAMP_OPT,
287 char *rv[2]; 299 CHECK_SOURCE_OPT,
288 300 };
289 int option = 0; 301 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
290 static struct option longopts[] = { 302 {"sourceip", required_argument, 0, 'S'},
291 {"hostname", required_argument, 0, 'H'}, 303 {"sourceif", required_argument, 0, 'I'},
292 {"sourceip", required_argument, 0, 'S'}, 304 {"critical", required_argument, 0, 'c'},
293 {"sourceif", required_argument, 0, 'I'}, 305 {"warning", required_argument, 0, 'w'},
294 {"critical", required_argument, 0, 'c'}, 306 {"alive", no_argument, 0, 'a'},
295 {"warning", required_argument, 0, 'w'}, 307 {"bytes", required_argument, 0, 'b'},
296 {"alive", no_argument, 0, 'a'}, 308 {"number", required_argument, 0, 'n'},
297 {"bytes", required_argument, 0, 'b'}, 309 {"target-timeout", required_argument, 0, 'T'},
298 {"number", required_argument, 0, 'n'}, 310 {"interval", required_argument, 0, 'i'},
299 {"target-timeout", required_argument, 0, 'T'}, 311 {"verbose", no_argument, 0, 'v'},
300 {"interval", required_argument, 0, 'i'}, 312 {"version", no_argument, 0, 'V'},
301 {"verbose", no_argument, 0, 'v'}, 313 {"help", no_argument, 0, 'h'},
302 {"version", no_argument, 0, 'V'}, 314 {"use-ipv4", no_argument, 0, '4'},
303 {"help", no_argument, 0, 'h'}, 315 {"use-ipv6", no_argument, 0, '6'},
304 {"use-ipv4", no_argument, 0, '4'}, 316 {"dontfrag", no_argument, 0, 'M'},
305 {"use-ipv6", no_argument, 0, '6'}, 317 {"random", no_argument, 0, 'R'},
306 {0, 0, 0, 0} 318#ifdef FPING_VERSION_5_2_OR_HIGHER
307 }; 319 // only available with fping version >= 5.2
308 320 {"fwmark", required_argument, NULL, FWMARK_OPT},
309 rv[PL] = NULL; 321# ifdef FPING_VERSION_5_3_OR_HIGHER
310 rv[RTA] = NULL; 322 // only available with fping version >= 5.3
311 323 {"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
312 if (argc < 2) 324 {"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
313 return ERROR; 325# endif
314
315 if (!is_option (argv[1])) {
316 server_name = argv[1];
317 argv[1] = argv[0];
318 argv = &argv[1];
319 argc--;
320 }
321
322 while (1) {
323 c = getopt_long (argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:46", longopts, &option);
324
325 if (c == -1 || c == EOF || c == 1)
326 break;
327
328 switch (c) {
329 case '?': /* print short usage statement if args not parsable */
330 usage5 ();
331 case 'a': /* host alive mode */
332 alive_p = true;
333 break;
334 case 'h': /* help */
335 print_help ();
336 exit (STATE_UNKNOWN);
337 case 'V': /* version */
338 print_revision (progname, NP_VERSION);
339 exit (STATE_UNKNOWN);
340 case 'v': /* verbose mode */
341 verbose = true;
342 break;
343 case 'H': /* hostname */
344 if (is_host (optarg) == false) {
345 usage2 (_("Invalid hostname/address"), optarg);
346 }
347 server_name = strscpy (server_name, optarg);
348 break;
349 case 'S': /* sourceip */
350 if (is_host (optarg) == false) {
351 usage2 (_("Invalid hostname/address"), optarg);
352 }
353 sourceip = strscpy (sourceip, optarg);
354 break;
355 case 'I': /* sourceip */
356 sourceif = strscpy (sourceif, optarg);
357 break;
358 case '4': /* IPv4 only */
359 address_family = AF_INET;
360 break;
361 case '6': /* IPv6 only */
362#ifdef USE_IPV6
363 address_family = AF_INET6;
364#else
365 usage (_("IPv6 support not available\n"));
366#endif 326#endif
367 break; 327 {0, 0, 0, 0}};
368 case 'c':
369 get_threshold (optarg, rv);
370 if (rv[RTA]) {
371 crta = strtod (rv[RTA], NULL);
372 crta_p = true;
373 rv[RTA] = NULL;
374 }
375 if (rv[PL]) {
376 cpl = atoi (rv[PL]);
377 cpl_p = true;
378 rv[PL] = NULL;
379 }
380 break;
381 case 'w':
382 get_threshold (optarg, rv);
383 if (rv[RTA]) {
384 wrta = strtod (rv[RTA], NULL);
385 wrta_p = true;
386 rv[RTA] = NULL;
387 }
388 if (rv[PL]) {
389 wpl = atoi (rv[PL]);
390 wpl_p = true;
391 rv[PL] = NULL;
392 }
393 break;
394 case 'b': /* bytes per packet */
395 if (is_intpos (optarg))
396 packet_size = atoi (optarg);
397 else
398 usage (_("Packet size must be a positive integer"));
399 break;
400 case 'n': /* number of packets */
401 if (is_intpos (optarg))
402 packet_count = atoi (optarg);
403 else
404 usage (_("Packet count must be a positive integer"));
405 break;
406 case 'T': /* timeout in msec */
407 if (is_intpos (optarg))
408 target_timeout = atoi (optarg);
409 else
410 usage (_("Target timeout must be a positive integer"));
411 break;
412 case 'i': /* interval in msec */
413 if (is_intpos (optarg))
414 packet_interval = atoi (optarg);
415 else
416 usage (_("Interval must be a positive integer"));
417 break;
418 }
419 }
420
421 if (server_name == NULL)
422 usage4 (_("Hostname was not supplied"));
423
424 return OK;
425}
426
427 328
428int 329 char *rv[2];
429get_threshold (char *arg, char *rv[2]) 330 rv[PL] = NULL;
430{ 331 rv[RTA] = NULL;
431 char *arg1 = NULL;
432 char *arg2 = NULL;
433
434 arg1 = strscpy (arg1, arg);
435 if (strpbrk (arg1, ",:"))
436 arg2 = 1 + strpbrk (arg1, ",:");
437
438 if (arg2) {
439 arg1[strcspn (arg1, ",:")] = 0;
440 if (strstr (arg1, "%") && strstr (arg2, "%"))
441 die (STATE_UNKNOWN,
442 _("%s: Only one threshold may be packet loss (%s)\n"), progname,
443 arg);
444 if (!strstr (arg1, "%") && !strstr (arg2, "%"))
445 die (STATE_UNKNOWN,
446 _("%s: Only one threshold must be packet loss (%s)\n"),
447 progname, arg);
448 }
449
450 if (arg2 && strstr (arg2, "%")) {
451 rv[PL] = arg2;
452 rv[RTA] = arg1;
453 }
454 else if (arg2) {
455 rv[PL] = arg1;
456 rv[RTA] = arg2;
457 }
458 else if (strstr (arg1, "%")) {
459 rv[PL] = arg1;
460 }
461 else {
462 rv[RTA] = arg1;
463 }
464
465 return OK;
466}
467 332
333 int option = 0;
468 334
469void print_help (void) { 335 check_fping_config_wrapper result = {
336 .errorcode = OK,
337 .config = check_fping_config_init(),
338 };
470 339
471 print_revision (progname, NP_VERSION); 340 if (argc < 2) {
341 result.errorcode = ERROR;
342 return result;
343 }
472 344
473 printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n"); 345 if (!is_option(argv[1])) {
474 printf (COPYRIGHT, copyright, email); 346 result.config.server_name = argv[1];
347 argv[1] = argv[0];
348 argv = &argv[1];
349 argc--;
350 }
475 351
476 printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check")); 352 while (true) {
353 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
477 354
478 printf ("%s\n", _("Note that it is necessary to set the suid flag on fping.")); 355 if (option_index == -1 || option_index == EOF || option_index == 1) {
356 break;
357 }
479 358
480 printf ("\n\n"); 359 switch (option_index) {
360 case '?': /* print short usage statement if args not parsable */
361 usage5();
362 case 'a': /* host alive mode */
363 result.config.alive_p = true;
364 break;
365 case 'h': /* help */
366 print_help();
367 exit(STATE_UNKNOWN);
368 case 'V': /* version */
369 print_revision(progname, NP_VERSION);
370 exit(STATE_UNKNOWN);
371 case 'v': /* verbose mode */
372 verbose = true;
373 break;
374 case 'H': /* hostname */
375 if (!is_host(optarg)) {
376 usage2(_("Invalid hostname/address"), optarg);
377 }
378 result.config.server_name = optarg;
379 break;
380 case 'S': /* sourceip */
381 if (!is_host(optarg)) {
382 usage2(_("Invalid hostname/address"), optarg);
383 }
384 result.config.sourceip = optarg;
385 break;
386 case 'I': /* sourceip */
387 result.config.sourceif = optarg;
388 break;
389 case '4': /* IPv4 only */
390 address_family = AF_INET;
391 break;
392 case '6': /* IPv6 only */
393 address_family = AF_INET6;
394 break;
395 case 'c':
396 get_threshold(optarg, rv);
397 if (rv[RTA]) {
398 result.config.crta = strtod(rv[RTA], NULL);
399 result.config.crta_p = true;
400 rv[RTA] = NULL;
401 }
402 if (rv[PL]) {
403 result.config.cpl = atoi(rv[PL]);
404 result.config.cpl_p = true;
405 rv[PL] = NULL;
406 }
407 break;
408 case 'w':
409 get_threshold(optarg, rv);
410 if (rv[RTA]) {
411 result.config.wrta = strtod(rv[RTA], NULL);
412 result.config.wrta_p = true;
413 rv[RTA] = NULL;
414 }
415 if (rv[PL]) {
416 result.config.wpl = atoi(rv[PL]);
417 result.config.wpl_p = true;
418 rv[PL] = NULL;
419 }
420 break;
421 case 'b': /* bytes per packet */
422 if (is_intpos(optarg)) {
423 result.config.packet_size = atoi(optarg);
424 } else {
425 usage(_("Packet size must be a positive integer"));
426 }
427 break;
428 case 'n': /* number of packets */
429 if (is_intpos(optarg)) {
430 result.config.packet_count = atoi(optarg);
431 } else {
432 usage(_("Packet count must be a positive integer"));
433 }
434 break;
435 case 'T': /* timeout in msec */
436 if (is_intpos(optarg)) {
437 result.config.target_timeout = atoi(optarg);
438 } else {
439 usage(_("Target timeout must be a positive integer"));
440 }
441 break;
442 case 'i': /* interval in msec */
443 if (is_intpos(optarg)) {
444 result.config.packet_interval = atoi(optarg);
445 } else {
446 usage(_("Interval must be a positive integer"));
447 }
448 break;
449 case 'R':
450 result.config.randomize_packet_data = true;
451 break;
452 case 'M':
453 result.config.dontfrag = true;
454 break;
455 case FWMARK_OPT:
456 if (is_intpos(optarg)) {
457 result.config.fwmark = (unsigned int)atol(optarg);
458 result.config.fwmark_set = true;
459 } else {
460 usage(_("fwmark must be a positive integer"));
461 }
462 break;
463 case ICMP_TIMESTAMP_OPT:
464 result.config.icmp_timestamp = true;
465 break;
466 case CHECK_SOURCE_OPT:
467 result.config.check_source = true;
468 break;
469 }
470 }
481 471
482 print_usage (); 472 if (result.config.server_name == NULL) {
473 usage4(_("Hostname was not supplied"));
474 }
483 475
484 printf (UT_HELP_VRSN); 476 return result;
485 printf (UT_EXTRA_OPTS); 477}
486 478
487 printf (UT_IPv46); 479int get_threshold(char *arg, char *rv[2]) {
480 char *arg2 = NULL;
481
482 char *arg1 = strdup(arg);
483 if (strpbrk(arg1, ",:")) {
484 arg2 = 1 + strpbrk(arg1, ",:");
485 }
486
487 if (arg2) {
488 arg1[strcspn(arg1, ",:")] = 0;
489 if (strstr(arg1, "%") && strstr(arg2, "%")) {
490 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg);
491 }
492 if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
493 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg);
494 }
495 }
496
497 if (arg2 && strstr(arg2, "%")) {
498 rv[PL] = arg2;
499 rv[RTA] = arg1;
500 } else if (arg2) {
501 rv[PL] = arg1;
502 rv[RTA] = arg2;
503 } else if (strstr(arg1, "%")) {
504 rv[PL] = arg1;
505 } else {
506 rv[RTA] = arg1;
507 }
508
509 return OK;
510}
488 511
489 printf (" %s\n", "-H, --hostname=HOST"); 512void print_help(void) {
490 printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)")); 513
491 printf (" %s\n", "-w, --warning=THRESHOLD"); 514 print_revision(progname, NP_VERSION);
492 printf (" %s\n", _("warning threshold pair")); 515
493 printf (" %s\n", "-c, --critical=THRESHOLD"); 516 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
494 printf (" %s\n", _("critical threshold pair")); 517 printf(COPYRIGHT, copyright, email);
495 printf (" %s\n", "-a, --alive"); 518
496 printf (" %s\n", _("Return OK after first successful reply")); 519 printf("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
497 printf (" %s\n", "-b, --bytes=INTEGER"); 520
498 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE); 521 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
499 printf (" %s\n", "-n, --number=INTEGER"); 522
500 printf (" %s (default: %d)\n", _("number of ICMP packets to send"),PACKET_COUNT); 523 printf("\n\n");
501 printf (" %s\n", "-T, --target-timeout=INTEGER"); 524
502 printf (" %s (default: fping's default for -t)\n", _("Target timeout (ms)")); 525 print_usage();
503 printf (" %s\n", "-i, --interval=INTEGER"); 526
504 printf (" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets")); 527 printf(UT_HELP_VRSN);
505 printf (" %s\n", "-S, --sourceip=HOST"); 528 printf(UT_EXTRA_OPTS);
506 printf (" %s\n", _("name or IP Address of sourceip")); 529
507 printf (" %s\n", "-I, --sourceif=IF"); 530 printf(UT_IPv46);
508 printf (" %s\n", _("source interface name")); 531
509 printf (UT_VERBOSE); 532 printf(" %s\n", "-H, --hostname=HOST");
510 printf ("\n"); 533 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
511 printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)")); 534 printf(" %s\n", "-w, --warning=THRESHOLD");
512 printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of")); 535 printf(" %s\n", _("warning threshold pair"));
513 printf (" %s\n", _("packet loss to trigger an alarm state.")); 536 printf(" %s\n", "-c, --critical=THRESHOLD");
537 printf(" %s\n", _("critical threshold pair"));
538 printf(" %s\n", "-a, --alive");
539 printf(" %s\n", _("Return OK after first successful reply"));
540 printf(" %s\n", "-b, --bytes=INTEGER");
541 printf(" %s (default: %d)\n", _("size of ICMP packet"), PACKET_SIZE);
542 printf(" %s\n", "-n, --number=INTEGER");
543 printf(" %s (default: %d)\n", _("number of ICMP packets to send"), PACKET_COUNT);
544 printf(" %s\n", "-T, --target-timeout=INTEGER");
545 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
546 printf(" %s\n", "-i, --interval=INTEGER");
547 printf(" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
548 printf(" %s\n", "-S, --sourceip=HOST");
549 printf(" %s\n", _("name or IP Address of sourceip"));
550 printf(" %s\n", "-I, --sourceif=IF");
551 printf(" %s\n", _("source interface name"));
552 printf(" %s\n", "-M, --dontfrag");
553 printf(" %s\n", _("set the Don't Fragment flag"));
554 printf(" %s\n", "-R, --random");
555 printf(" %s\n", _("random packet data (to foil link data compression)"));
556#ifdef FPING_VERSION_5_2_OR_HIGHER
557 printf(" %s\n", "--fwmark=INTEGER");
558 printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
559# ifdef FPING_VERSION_5_3_OR_HIGHER
560 printf(" %s\n", "--icmp-timestamp");
561 printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
562 printf(" %s\n", "--check-source");
563 printf(" %s\n", _("discard replies not from target address (fping option)"));
564# endif
565#endif
566 printf(UT_VERBOSE);
567 printf("\n");
568 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
569 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
570 printf(" %s\n", _("packet loss to trigger an alarm state."));
514 571
515 printf ("\n"); 572 printf("\n");
516 printf (" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6.")); 573 printf(" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
517 574
518 printf (UT_SUPPORT); 575 printf(UT_SUPPORT);
519} 576}
520 577
521 578void print_usage(void) {
522void 579 printf("%s\n", _("Usage:"));
523print_usage (void) 580 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
524{
525 printf ("%s\n", _("Usage:"));
526 printf (" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
527} 581}