diff options
Diffstat (limited to 'plugins/check_ping.c')
-rw-r--r-- | plugins/check_ping.c | 580 |
1 files changed, 344 insertions, 236 deletions
diff --git a/plugins/check_ping.c b/plugins/check_ping.c index 4aafaf41..61feb958 100644 --- a/plugins/check_ping.c +++ b/plugins/check_ping.c | |||
@@ -36,61 +36,52 @@ const char *email = "devel@monitoring-plugins.org"; | |||
36 | #include "netutils.h" | 36 | #include "netutils.h" |
37 | #include "popen.h" | 37 | #include "popen.h" |
38 | #include "utils.h" | 38 | #include "utils.h" |
39 | #include "check_ping.d/config.h" | ||
40 | #include "../lib/states.h" | ||
39 | 41 | ||
40 | #include <signal.h> | 42 | #include <signal.h> |
41 | 43 | ||
42 | #define WARN_DUPLICATES "DUPLICATES FOUND! " | 44 | #define WARN_DUPLICATES "DUPLICATES FOUND! " |
43 | #define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */ | ||
44 | 45 | ||
45 | enum { | 46 | typedef struct { |
46 | UNKNOWN_PACKET_LOSS = 200, /* 200% */ | 47 | int errorcode; |
47 | DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */ | 48 | check_ping_config config; |
48 | }; | 49 | } check_ping_config_wrapper; |
50 | static check_ping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | ||
51 | static check_ping_config_wrapper validate_arguments(check_ping_config_wrapper /*config_wrapper*/); | ||
49 | 52 | ||
50 | static int process_arguments(int /*argc*/, char ** /*argv*/); | 53 | static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/); |
51 | static int get_threshold(char * /*arg*/, float * /*trta*/, int * /*tpl*/); | 54 | |
52 | static int validate_arguments(void); | 55 | typedef struct { |
53 | static int run_ping(const char *cmd, const char *addr); | 56 | mp_state_enum state; |
54 | static int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr); | 57 | double round_trip_average; |
58 | int packet_loss; | ||
59 | } ping_result; | ||
60 | static ping_result run_ping(const char *cmd, const char *addr, double /*crta*/); | ||
61 | |||
62 | static mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr); | ||
55 | static void print_help(void); | 63 | static void print_help(void); |
56 | void print_usage(void); | 64 | void print_usage(void); |
57 | 65 | ||
58 | static bool display_html = false; | ||
59 | static int wpl = UNKNOWN_PACKET_LOSS; | ||
60 | static int cpl = UNKNOWN_PACKET_LOSS; | ||
61 | static float wrta = UNKNOWN_TRIP_TIME; | ||
62 | static float crta = UNKNOWN_TRIP_TIME; | ||
63 | static char **addresses = NULL; | ||
64 | static int n_addresses = 0; | ||
65 | static int max_addr = 1; | ||
66 | static int max_packets = -1; | ||
67 | static int verbose = 0; | 66 | static int verbose = 0; |
68 | 67 | ||
69 | static float rta = UNKNOWN_TRIP_TIME; | ||
70 | static int pl = UNKNOWN_PACKET_LOSS; | ||
71 | |||
72 | static char *warn_text; | 68 | static char *warn_text; |
73 | 69 | ||
74 | int main(int argc, char **argv) { | 70 | int main(int argc, char **argv) { |
75 | char *cmd = NULL; | ||
76 | char *rawcmd = NULL; | ||
77 | int result = STATE_UNKNOWN; | ||
78 | int this_result = STATE_UNKNOWN; | ||
79 | int i; | ||
80 | |||
81 | setlocale(LC_ALL, ""); | 71 | setlocale(LC_ALL, ""); |
82 | setlocale(LC_NUMERIC, "C"); | 72 | setlocale(LC_NUMERIC, "C"); |
83 | bindtextdomain(PACKAGE, LOCALEDIR); | 73 | bindtextdomain(PACKAGE, LOCALEDIR); |
84 | textdomain(PACKAGE); | 74 | textdomain(PACKAGE); |
85 | 75 | ||
86 | addresses = malloc(sizeof(char *) * max_addr); | ||
87 | addresses[0] = NULL; | ||
88 | |||
89 | /* Parse extra opts if any */ | 76 | /* Parse extra opts if any */ |
90 | argv = np_extra_opts(&argc, argv, progname); | 77 | argv = np_extra_opts(&argc, argv, progname); |
91 | 78 | ||
92 | if (process_arguments(argc, argv) == ERROR) | 79 | check_ping_config_wrapper tmp_config = process_arguments(argc, argv); |
80 | if (tmp_config.errorcode == ERROR) { | ||
93 | usage4(_("Could not parse arguments")); | 81 | usage4(_("Could not parse arguments")); |
82 | } | ||
83 | |||
84 | const check_ping_config config = tmp_config.config; | ||
94 | 85 | ||
95 | /* Set signal handling and alarm */ | 86 | /* Set signal handling and alarm */ |
96 | if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { | 87 | if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { |
@@ -105,71 +96,90 @@ int main(int argc, char **argv) { | |||
105 | alarm(timeout_interval); | 96 | alarm(timeout_interval); |
106 | #endif | 97 | #endif |
107 | 98 | ||
108 | for (i = 0; i < n_addresses; i++) { | 99 | int result = STATE_UNKNOWN; |
109 | 100 | char *rawcmd = NULL; | |
101 | for (size_t i = 0; i < config.n_addresses; i++) { | ||
110 | #ifdef PING6_COMMAND | 102 | #ifdef PING6_COMMAND |
111 | if (address_family != AF_INET && is_inet6_addr(addresses[i])) | 103 | if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) { |
112 | rawcmd = strdup(PING6_COMMAND); | 104 | rawcmd = strdup(PING6_COMMAND); |
113 | else | 105 | } else { |
114 | rawcmd = strdup(PING_COMMAND); | 106 | rawcmd = strdup(PING_COMMAND); |
107 | } | ||
115 | #else | 108 | #else |
116 | rawcmd = strdup(PING_COMMAND); | 109 | rawcmd = strdup(PING_COMMAND); |
117 | #endif | 110 | #endif |
118 | 111 | ||
119 | /* does the host address of number of packets argument come first? */ | 112 | char *cmd = NULL; |
113 | |||
114 | /* does the host address of number of packets argument come first? */ | ||
120 | #ifdef PING_PACKETS_FIRST | 115 | #ifdef PING_PACKETS_FIRST |
121 | # ifdef PING_HAS_TIMEOUT | 116 | # ifdef PING_HAS_TIMEOUT |
122 | xasprintf(&cmd, rawcmd, timeout_interval, max_packets, addresses[i]); | 117 | xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]); |
123 | # else | 118 | # else |
124 | xasprintf(&cmd, rawcmd, max_packets, addresses[i]); | 119 | xasprintf(&cmd, rawcmd, config.max_packets, config.addresses[i]); |
125 | # endif | 120 | # endif |
126 | #else | 121 | #else |
127 | xasprintf(&cmd, rawcmd, addresses[i], max_packets); | 122 | xasprintf(&cmd, rawcmd, config.addresses[i], config.max_packets); |
128 | #endif | 123 | #endif |
129 | 124 | ||
130 | if (verbose >= 2) | 125 | if (verbose >= 2) { |
131 | printf("CMD: %s\n", cmd); | 126 | printf("CMD: %s\n", cmd); |
127 | } | ||
132 | 128 | ||
133 | /* run the command */ | 129 | /* run the command */ |
134 | this_result = run_ping(cmd, addresses[i]); | ||
135 | 130 | ||
136 | if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { | 131 | ping_result pinged = run_ping(cmd, config.addresses[i], config.crta); |
132 | |||
133 | if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) { | ||
137 | printf("%s\n", cmd); | 134 | printf("%s\n", cmd); |
138 | die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n")); | 135 | die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n")); |
139 | } | 136 | } |
140 | 137 | ||
141 | if (pl >= cpl || rta >= crta || rta < 0) | 138 | if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta || |
142 | this_result = STATE_CRITICAL; | 139 | pinged.round_trip_average < 0) { |
143 | else if (pl >= wpl || rta >= wrta) | 140 | pinged.state = STATE_CRITICAL; |
144 | this_result = STATE_WARNING; | 141 | } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) { |
145 | else if (pl >= 0 && rta >= 0) | 142 | pinged.state = STATE_WARNING; |
146 | this_result = max_state(STATE_OK, this_result); | 143 | } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) { |
147 | 144 | pinged.state = max_state(STATE_OK, pinged.state); | |
148 | if (n_addresses > 1 && this_result != STATE_UNKNOWN) | 145 | } |
149 | die(STATE_OK, "%s is alive\n", addresses[i]); | 146 | |
150 | 147 | if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) { | |
151 | if (display_html == true) | 148 | die(STATE_OK, "%s is alive\n", config.addresses[i]); |
152 | printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); | 149 | } |
153 | if (pl == 100) | 150 | |
154 | printf(_("PING %s - %sPacket loss = %d%%"), state_text(this_result), warn_text, pl); | 151 | if (config.display_html) { |
155 | else | 152 | printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]); |
156 | printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(this_result), warn_text, pl, rta); | 153 | } |
157 | if (display_html == true) | 154 | if (pinged.packet_loss == 100) { |
155 | printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text, | ||
156 | pinged.packet_loss); | ||
157 | } else { | ||
158 | printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state), | ||
159 | warn_text, pinged.packet_loss, pinged.round_trip_average); | ||
160 | } | ||
161 | if (config.display_html) { | ||
158 | printf("</A>"); | 162 | printf("</A>"); |
163 | } | ||
159 | 164 | ||
160 | /* Print performance data */ | 165 | /* Print performance data */ |
161 | if (pl != 100) { | 166 | if (pinged.packet_loss != 100) { |
162 | printf("|%s", | 167 | printf("|%s", |
163 | fperfdata("rta", (double)rta, "ms", wrta > 0 ? true : false, wrta, crta > 0 ? true : false, crta, true, 0, false, 0)); | 168 | fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0), |
169 | config.wrta, (bool)(config.crta > 0), config.crta, true, 0, false, 0)); | ||
164 | } else { | 170 | } else { |
165 | printf("| rta=U;%f;%f;;", wrta, crta); | 171 | printf("| rta=U;%f;%f;;", config.wrta, config.crta); |
166 | } | 172 | } |
167 | printf(" %s\n", perfdata("pl", (long)pl, "%", wpl > 0 ? true : false, wpl, cpl > 0 ? true : false, cpl, true, 0, false, 0)); | ||
168 | 173 | ||
169 | if (verbose >= 2) | 174 | printf(" %s\n", |
170 | printf("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); | 175 | perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl, |
176 | (bool)(config.cpl > 0), config.cpl, true, 0, false, 0)); | ||
177 | |||
178 | if (verbose >= 2) { | ||
179 | printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl); | ||
180 | } | ||
171 | 181 | ||
172 | result = max_state(result, this_result); | 182 | result = max_state(result, pinged.state); |
173 | free(rawcmd); | 183 | free(rawcmd); |
174 | free(cmd); | 184 | free(cmd); |
175 | } | 185 | } |
@@ -178,11 +188,7 @@ int main(int argc, char **argv) { | |||
178 | } | 188 | } |
179 | 189 | ||
180 | /* process command-line arguments */ | 190 | /* process command-line arguments */ |
181 | int process_arguments(int argc, char **argv) { | 191 | check_ping_config_wrapper process_arguments(int argc, char **argv) { |
182 | int c = 1; | ||
183 | char *ptr; | ||
184 | |||
185 | int option = 0; | ||
186 | static struct option longopts[] = {STD_LONG_OPTS, | 192 | static struct option longopts[] = {STD_LONG_OPTS, |
187 | {"packets", required_argument, 0, 'p'}, | 193 | {"packets", required_argument, 0, 'p'}, |
188 | {"nohtml", no_argument, 0, 'n'}, | 194 | {"nohtml", no_argument, 0, 'n'}, |
@@ -191,23 +197,35 @@ int process_arguments(int argc, char **argv) { | |||
191 | {"use-ipv6", no_argument, 0, '6'}, | 197 | {"use-ipv6", no_argument, 0, '6'}, |
192 | {0, 0, 0, 0}}; | 198 | {0, 0, 0, 0}}; |
193 | 199 | ||
194 | if (argc < 2) | 200 | check_ping_config_wrapper result = { |
195 | return ERROR; | 201 | .errorcode = OK, |
202 | .config = check_ping_config_init(), | ||
203 | }; | ||
204 | |||
205 | if (argc < 2) { | ||
206 | result.errorcode = ERROR; | ||
207 | return result; | ||
208 | } | ||
196 | 209 | ||
197 | for (c = 1; c < argc; c++) { | 210 | for (int index = 1; index < argc; index++) { |
198 | if (strcmp("-to", argv[c]) == 0) | 211 | if (strcmp("-to", argv[index]) == 0) { |
199 | strcpy(argv[c], "-t"); | 212 | strcpy(argv[index], "-t"); |
200 | if (strcmp("-nohtml", argv[c]) == 0) | 213 | } |
201 | strcpy(argv[c], "-n"); | 214 | if (strcmp("-nohtml", argv[index]) == 0) { |
215 | strcpy(argv[index], "-n"); | ||
216 | } | ||
202 | } | 217 | } |
203 | 218 | ||
204 | while (1) { | 219 | int option = 0; |
205 | c = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); | 220 | size_t max_addr = MAX_ADDR_START; |
221 | while (true) { | ||
222 | int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); | ||
206 | 223 | ||
207 | if (c == -1 || c == EOF) | 224 | if (option_index == -1 || option_index == EOF) { |
208 | break; | 225 | break; |
226 | } | ||
209 | 227 | ||
210 | switch (c) { | 228 | switch (option_index) { |
211 | case '?': /* usage */ | 229 | case '?': /* usage */ |
212 | usage5(); | 230 | usage5(); |
213 | case 'h': /* help */ | 231 | case 'h': /* help */ |
@@ -234,17 +252,19 @@ int process_arguments(int argc, char **argv) { | |||
234 | usage(_("IPv6 support not available\n")); | 252 | usage(_("IPv6 support not available\n")); |
235 | #endif | 253 | #endif |
236 | break; | 254 | break; |
237 | case 'H': /* hostname */ | 255 | case 'H': /* hostname */ { |
238 | ptr = optarg; | 256 | char *ptr = optarg; |
239 | while (1) { | 257 | while (true) { |
240 | n_addresses++; | 258 | result.config.n_addresses++; |
241 | if (n_addresses > max_addr) { | 259 | if (result.config.n_addresses > max_addr) { |
242 | max_addr *= 2; | 260 | max_addr *= 2; |
243 | addresses = realloc(addresses, sizeof(char *) * max_addr); | 261 | result.config.addresses = |
244 | if (addresses == NULL) | 262 | realloc(result.config.addresses, sizeof(char *) * max_addr); |
263 | if (result.config.addresses == NULL) { | ||
245 | die(STATE_UNKNOWN, _("Could not realloc() addresses\n")); | 264 | die(STATE_UNKNOWN, _("Could not realloc() addresses\n")); |
265 | } | ||
246 | } | 266 | } |
247 | addresses[n_addresses - 1] = ptr; | 267 | result.config.addresses[result.config.n_addresses - 1] = ptr; |
248 | if ((ptr = index(ptr, ','))) { | 268 | if ((ptr = index(ptr, ','))) { |
249 | strcpy(ptr, ""); | 269 | strcpy(ptr, ""); |
250 | ptr += sizeof(char); | 270 | ptr += sizeof(char); |
@@ -252,219 +272,302 @@ int process_arguments(int argc, char **argv) { | |||
252 | break; | 272 | break; |
253 | } | 273 | } |
254 | } | 274 | } |
255 | break; | 275 | } break; |
256 | case 'p': /* number of packets to send */ | 276 | case 'p': /* number of packets to send */ |
257 | if (is_intnonneg(optarg)) | 277 | if (is_intnonneg(optarg)) { |
258 | max_packets = atoi(optarg); | 278 | result.config.max_packets = atoi(optarg); |
259 | else | 279 | } else { |
260 | usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg); | 280 | usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg); |
281 | } | ||
261 | break; | 282 | break; |
262 | case 'n': /* no HTML */ | 283 | case 'n': /* no HTML */ |
263 | display_html = false; | 284 | result.config.display_html = false; |
264 | break; | 285 | break; |
265 | case 'L': /* show HTML */ | 286 | case 'L': /* show HTML */ |
266 | display_html = true; | 287 | result.config.display_html = true; |
267 | break; | 288 | break; |
268 | case 'c': | 289 | case 'c': |
269 | get_threshold(optarg, &crta, &cpl); | 290 | get_threshold(optarg, &result.config.crta, &result.config.cpl); |
270 | break; | 291 | break; |
271 | case 'w': | 292 | case 'w': |
272 | get_threshold(optarg, &wrta, &wpl); | 293 | get_threshold(optarg, &result.config.wrta, &result.config.wpl); |
273 | break; | 294 | break; |
274 | } | 295 | } |
275 | } | 296 | } |
276 | 297 | ||
277 | c = optind; | 298 | int arg_counter = optind; |
278 | if (c == argc) | 299 | if (arg_counter == argc) { |
279 | return validate_arguments(); | 300 | return validate_arguments(result); |
301 | } | ||
280 | 302 | ||
281 | if (addresses[0] == NULL) { | 303 | if (result.config.addresses[0] == NULL) { |
282 | if (!is_host(argv[c])) { | 304 | if (!is_host(argv[arg_counter])) { |
283 | usage2(_("Invalid hostname/address"), argv[c]); | 305 | usage2(_("Invalid hostname/address"), argv[arg_counter]); |
284 | } else { | 306 | } else { |
285 | addresses[0] = argv[c++]; | 307 | result.config.addresses[0] = argv[arg_counter++]; |
286 | n_addresses++; | 308 | result.config.n_addresses++; |
287 | if (c == argc) | 309 | if (arg_counter == argc) { |
288 | return validate_arguments(); | 310 | return validate_arguments(result); |
311 | } | ||
289 | } | 312 | } |
290 | } | 313 | } |
291 | 314 | ||
292 | if (wpl == UNKNOWN_PACKET_LOSS) { | 315 | if (result.config.wpl == UNKNOWN_PACKET_LOSS) { |
293 | if (!is_intpercent(argv[c])) { | 316 | if (!is_intpercent(argv[arg_counter])) { |
294 | printf(_("<wpl> (%s) must be an integer percentage\n"), argv[c]); | 317 | printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]); |
295 | return ERROR; | 318 | result.errorcode = ERROR; |
296 | } else { | 319 | return result; |
297 | wpl = atoi(argv[c++]); | 320 | } |
298 | if (c == argc) | 321 | result.config.wpl = atoi(argv[arg_counter++]); |
299 | return validate_arguments(); | 322 | if (arg_counter == argc) { |
323 | return validate_arguments(result); | ||
300 | } | 324 | } |
301 | } | 325 | } |
302 | 326 | ||
303 | if (cpl == UNKNOWN_PACKET_LOSS) { | 327 | if (result.config.cpl == UNKNOWN_PACKET_LOSS) { |
304 | if (!is_intpercent(argv[c])) { | 328 | if (!is_intpercent(argv[arg_counter])) { |
305 | printf(_("<cpl> (%s) must be an integer percentage\n"), argv[c]); | 329 | printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]); |
306 | return ERROR; | 330 | result.errorcode = ERROR; |
307 | } else { | 331 | return result; |
308 | cpl = atoi(argv[c++]); | 332 | } |
309 | if (c == argc) | 333 | result.config.cpl = atoi(argv[arg_counter++]); |
310 | return validate_arguments(); | 334 | if (arg_counter == argc) { |
335 | return validate_arguments(result); | ||
311 | } | 336 | } |
312 | } | 337 | } |
313 | 338 | ||
314 | if (wrta < 0.0) { | 339 | if (result.config.wrta < 0.0) { |
315 | if (is_negative(argv[c])) { | 340 | if (is_negative(argv[arg_counter])) { |
316 | printf(_("<wrta> (%s) must be a non-negative number\n"), argv[c]); | 341 | printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]); |
317 | return ERROR; | 342 | result.errorcode = ERROR; |
318 | } else { | 343 | return result; |
319 | wrta = atof(argv[c++]); | 344 | } |
320 | if (c == argc) | 345 | result.config.wrta = atof(argv[arg_counter++]); |
321 | return validate_arguments(); | 346 | if (arg_counter == argc) { |
347 | return validate_arguments(result); | ||
322 | } | 348 | } |
323 | } | 349 | } |
324 | 350 | ||
325 | if (crta < 0.0) { | 351 | if (result.config.crta < 0.0) { |
326 | if (is_negative(argv[c])) { | 352 | if (is_negative(argv[arg_counter])) { |
327 | printf(_("<crta> (%s) must be a non-negative number\n"), argv[c]); | 353 | printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]); |
328 | return ERROR; | 354 | result.errorcode = ERROR; |
329 | } else { | 355 | return result; |
330 | crta = atof(argv[c++]); | 356 | } |
331 | if (c == argc) | 357 | result.config.crta = atof(argv[arg_counter++]); |
332 | return validate_arguments(); | 358 | if (arg_counter == argc) { |
359 | return validate_arguments(result); | ||
333 | } | 360 | } |
334 | } | 361 | } |
335 | 362 | ||
336 | if (max_packets == -1) { | 363 | if (result.config.max_packets == -1) { |
337 | if (is_intnonneg(argv[c])) { | 364 | if (is_intnonneg(argv[arg_counter])) { |
338 | max_packets = atoi(argv[c++]); | 365 | result.config.max_packets = atoi(argv[arg_counter++]); |
339 | } else { | 366 | } else { |
340 | printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[c]); | 367 | printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]); |
341 | return ERROR; | 368 | result.errorcode = ERROR; |
369 | return result; | ||
342 | } | 370 | } |
343 | } | 371 | } |
344 | 372 | ||
345 | return validate_arguments(); | 373 | return validate_arguments(result); |
346 | } | 374 | } |
347 | 375 | ||
348 | int get_threshold(char *arg, float *trta, int *tpl) { | 376 | int get_threshold(char *arg, double *trta, int *tpl) { |
349 | if (is_intnonneg(arg) && sscanf(arg, "%f", trta) == 1) | 377 | if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) { |
350 | return OK; | 378 | return OK; |
351 | else if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%f%*[:,]%d%%", trta, tpl) == 2) | 379 | } |
380 | |||
381 | if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) { | ||
352 | return OK; | 382 | return OK; |
353 | else if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) | 383 | } |
384 | |||
385 | if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) { | ||
354 | return OK; | 386 | return OK; |
387 | } | ||
355 | 388 | ||
356 | usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg); | 389 | usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg); |
357 | return STATE_UNKNOWN; | 390 | return STATE_UNKNOWN; |
358 | } | 391 | } |
359 | 392 | ||
360 | int validate_arguments() { | 393 | check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) { |
361 | float max_seconds; | 394 | if (config_wrapper.config.wrta < 0.0) { |
362 | int i; | ||
363 | |||
364 | if (wrta < 0.0) { | ||
365 | printf(_("<wrta> was not set\n")); | 395 | printf(_("<wrta> was not set\n")); |
366 | return ERROR; | 396 | config_wrapper.errorcode = ERROR; |
367 | } else if (crta < 0.0) { | 397 | return config_wrapper; |
398 | } | ||
399 | |||
400 | if (config_wrapper.config.crta < 0.0) { | ||
368 | printf(_("<crta> was not set\n")); | 401 | printf(_("<crta> was not set\n")); |
369 | return ERROR; | 402 | config_wrapper.errorcode = ERROR; |
370 | } else if (wpl == UNKNOWN_PACKET_LOSS) { | 403 | return config_wrapper; |
404 | } | ||
405 | |||
406 | if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) { | ||
371 | printf(_("<wpl> was not set\n")); | 407 | printf(_("<wpl> was not set\n")); |
372 | return ERROR; | 408 | config_wrapper.errorcode = ERROR; |
373 | } else if (cpl == UNKNOWN_PACKET_LOSS) { | 409 | return config_wrapper; |
410 | } | ||
411 | |||
412 | if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) { | ||
374 | printf(_("<cpl> was not set\n")); | 413 | printf(_("<cpl> was not set\n")); |
375 | return ERROR; | 414 | config_wrapper.errorcode = ERROR; |
376 | } else if (wrta > crta) { | 415 | return config_wrapper; |
377 | printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); | 416 | } |
378 | return ERROR; | 417 | |
379 | } else if (wpl > cpl) { | 418 | if (config_wrapper.config.wrta > config_wrapper.config.crta) { |
380 | printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); | 419 | printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta, |
381 | return ERROR; | 420 | config_wrapper.config.crta); |
421 | config_wrapper.errorcode = ERROR; | ||
422 | return config_wrapper; | ||
382 | } | 423 | } |
383 | 424 | ||
384 | if (max_packets == -1) | 425 | if (config_wrapper.config.wpl > config_wrapper.config.cpl) { |
385 | max_packets = DEFAULT_MAX_PACKETS; | 426 | printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl, |
427 | config_wrapper.config.cpl); | ||
428 | config_wrapper.errorcode = ERROR; | ||
429 | return config_wrapper; | ||
430 | } | ||
386 | 431 | ||
387 | max_seconds = crta / 1000.0 * max_packets + max_packets; | 432 | if (config_wrapper.config.max_packets == -1) { |
388 | if (max_seconds > timeout_interval) | 433 | config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS; |
389 | timeout_interval = (int)max_seconds; | 434 | } |
390 | 435 | ||
391 | for (i = 0; i < n_addresses; i++) { | 436 | double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) + |
392 | if (!is_host(addresses[i])) | 437 | config_wrapper.config.max_packets; |
393 | usage2(_("Invalid hostname/address"), addresses[i]); | 438 | if (max_seconds > timeout_interval) { |
439 | timeout_interval = (unsigned int)max_seconds; | ||
440 | } | ||
441 | |||
442 | for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) { | ||
443 | if (!is_host(config_wrapper.config.addresses[i])) { | ||
444 | usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]); | ||
445 | } | ||
394 | } | 446 | } |
395 | 447 | ||
396 | if (n_addresses == 0) { | 448 | if (config_wrapper.config.n_addresses == 0) { |
397 | usage(_("You must specify a server address or host name")); | 449 | usage(_("You must specify a server address or host name")); |
398 | } | 450 | } |
399 | 451 | ||
400 | return OK; | 452 | return config_wrapper; |
401 | } | 453 | } |
402 | 454 | ||
403 | int run_ping(const char *cmd, const char *addr) { | 455 | ping_result run_ping(const char *cmd, const char *addr, double crta) { |
404 | char buf[MAX_INPUT_BUFFER]; | 456 | if ((child_process = spopen(cmd)) == NULL) { |
405 | int result = STATE_UNKNOWN; | ||
406 | int match; | ||
407 | |||
408 | if ((child_process = spopen(cmd)) == NULL) | ||
409 | die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); | 457 | die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); |
458 | } | ||
410 | 459 | ||
411 | child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); | 460 | child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); |
412 | if (child_stderr == NULL) | 461 | if (child_stderr == NULL) { |
413 | printf(_("Cannot open stderr for %s\n"), cmd); | 462 | printf(_("Cannot open stderr for %s\n"), cmd); |
463 | } | ||
414 | 464 | ||
415 | while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) { | 465 | char buf[MAX_INPUT_BUFFER]; |
466 | ping_result result = { | ||
467 | .state = STATE_UNKNOWN, | ||
468 | .packet_loss = UNKNOWN_PACKET_LOSS, | ||
469 | .round_trip_average = UNKNOWN_TRIP_TIME, | ||
470 | }; | ||
416 | 471 | ||
417 | if (verbose >= 3) | 472 | while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) { |
473 | if (verbose >= 3) { | ||
418 | printf("Output: %s", buf); | 474 | printf("Output: %s", buf); |
475 | } | ||
419 | 476 | ||
420 | result = max_state(result, error_scan(buf, addr)); | 477 | result.state = max_state(result.state, error_scan(buf, addr)); |
421 | 478 | ||
422 | /* get the percent loss statistics */ | 479 | /* get the percent loss statistics */ |
423 | match = 0; | 480 | int match = 0; |
424 | if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || | 481 | if ((sscanf( |
425 | (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || | 482 | buf, |
426 | (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || | 483 | "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", |
427 | (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &pl, &match) && match) || | 484 | &result.packet_loss, &match) == 1 && |
428 | (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &pl, &match) && match) || | 485 | match) || |
429 | (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &pl, &match) && match) || | 486 | (sscanf(buf, |
430 | (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &pl, &match) && match) || | 487 | "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet " |
431 | (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || | 488 | "loss%n", |
432 | (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || | 489 | &result.packet_loss, &match) == 1 && |
433 | (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &pl, &match) && match)) | 490 | match) || |
491 | (sscanf(buf, | ||
492 | "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", | ||
493 | &result.packet_loss, &match) == 1 && | ||
494 | match) || | ||
495 | (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", | ||
496 | &result.packet_loss, &match) == 1 && | ||
497 | match) || | ||
498 | (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", | ||
499 | &result.packet_loss, &match) == 1 && | ||
500 | match) || | ||
501 | (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", | ||
502 | &result.packet_loss, &match) == 1 && | ||
503 | match) || | ||
504 | (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", | ||
505 | &result.packet_loss, &match) == 1 && | ||
506 | match) == 1 || | ||
507 | (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", | ||
508 | &result.packet_loss, &match) == 1 && | ||
509 | match) || | ||
510 | (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", | ||
511 | &result.packet_loss, &match) == 1 && | ||
512 | match) || | ||
513 | (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) { | ||
434 | continue; | 514 | continue; |
515 | } | ||
435 | 516 | ||
436 | /* get the round trip average */ | 517 | /* get the round trip average */ |
437 | else if ((sscanf(buf, "round-trip min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || | 518 | if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, |
438 | (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || | 519 | &match) == 1 && |
439 | (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || | 520 | match) || |
440 | (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || | 521 | (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n", |
441 | (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || | 522 | &result.round_trip_average, &match) == 1 && |
442 | (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || | 523 | match) || |
443 | (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || | 524 | (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n", |
444 | (sscanf(buf, "rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n", &rta, &match) && match) || | 525 | &result.round_trip_average, &match) == 1 && |
445 | (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)) | 526 | match) || |
527 | (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n", | ||
528 | &result.round_trip_average, &match) == 1 && | ||
529 | match) || | ||
530 | (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n", | ||
531 | &result.round_trip_average, &match) == 1 && | ||
532 | match) || | ||
533 | (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, | ||
534 | &match) == 1 && | ||
535 | match) || | ||
536 | (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n", | ||
537 | &result.round_trip_average, &match) == 1 && | ||
538 | match) || | ||
539 | (sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average, | ||
540 | &match) == 1 && | ||
541 | match) || | ||
542 | (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n", | ||
543 | &result.round_trip_average, &match) == 1 && | ||
544 | match)) { | ||
446 | continue; | 545 | continue; |
546 | } | ||
447 | } | 547 | } |
448 | 548 | ||
449 | /* this is needed because there is no rta if all packets are lost */ | 549 | /* this is needed because there is no rta if all packets are lost */ |
450 | if (pl == 100) | 550 | if (result.packet_loss == 100) { |
451 | rta = crta; | 551 | result.round_trip_average = crta; |
552 | } | ||
452 | 553 | ||
453 | /* check stderr, setting at least WARNING if there is output here */ | 554 | /* check stderr, setting at least WARNING if there is output here */ |
454 | /* Add warning into warn_text */ | 555 | /* Add warning into warn_text */ |
455 | while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) { | 556 | while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) { |
456 | if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") && !strstr(buf, "Warning: time of day goes back") | 557 | if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") && |
558 | !strstr(buf, "Warning: time of day goes back") | ||
457 | 559 | ||
458 | ) { | 560 | ) { |
459 | if (verbose >= 3) { | 561 | if (verbose >= 3) { |
460 | printf("Got stderr: %s", buf); | 562 | printf("Got stderr: %s", buf); |
461 | } | 563 | } |
462 | if ((result = error_scan(buf, addr)) == STATE_OK) { | 564 | if ((result.state = error_scan(buf, addr)) == STATE_OK) { |
463 | result = STATE_WARNING; | 565 | result.state = STATE_WARNING; |
464 | if (warn_text == NULL) { | 566 | if (warn_text == NULL) { |
465 | warn_text = strdup(_("System call sent warnings to stderr ")); | 567 | warn_text = strdup(_("System call sent warnings to stderr ")); |
466 | } else { | 568 | } else { |
467 | xasprintf(&warn_text, "%s %s", warn_text, _("System call sent warnings to stderr ")); | 569 | xasprintf(&warn_text, "%s %s", warn_text, |
570 | _("System call sent warnings to stderr ")); | ||
468 | } | 571 | } |
469 | } | 572 | } |
470 | } | 573 | } |
@@ -474,43 +577,48 @@ int run_ping(const char *cmd, const char *addr) { | |||
474 | 577 | ||
475 | spclose(child_process); | 578 | spclose(child_process); |
476 | 579 | ||
477 | if (warn_text == NULL) | 580 | if (warn_text == NULL) { |
478 | warn_text = strdup(""); | 581 | warn_text = strdup(""); |
582 | } | ||
479 | 583 | ||
480 | return result; | 584 | return result; |
481 | } | 585 | } |
482 | 586 | ||
483 | int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) { | 587 | mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) { |
484 | if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) | 588 | if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || |
589 | strstr(buf, "No route")) { | ||
485 | die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr); | 590 | die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr); |
486 | else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) | 591 | } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) { |
487 | die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr); | 592 | die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr); |
488 | else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) | 593 | } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) { |
489 | die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr); | 594 | die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr); |
490 | else if (strstr(buf, "Destination Protocol Unreachable")) | 595 | } else if (strstr(buf, "Destination Protocol Unreachable")) { |
491 | die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr); | 596 | die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr); |
492 | else if (strstr(buf, "Destination Net Prohibited")) | 597 | } else if (strstr(buf, "Destination Net Prohibited")) { |
493 | die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr); | 598 | die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr); |
494 | else if (strstr(buf, "Destination Host Prohibited")) | 599 | } else if (strstr(buf, "Destination Host Prohibited")) { |
495 | die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr); | 600 | die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr); |
496 | else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) | 601 | } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) { |
497 | die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr); | 602 | die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr); |
498 | else if (strstr(buf, "unknown host")) | 603 | } else if (strstr(buf, "unknown host")) { |
499 | die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr); | 604 | die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr); |
500 | else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) | 605 | } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) { |
501 | die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr); | 606 | die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr); |
502 | else if (strstr(buf, "Destination unreachable: ")) | 607 | } else if (strstr(buf, "Destination unreachable: ")) { |
503 | die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr); | 608 | die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr); |
609 | } | ||
504 | 610 | ||
505 | if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) { | 611 | if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) { |
506 | if (warn_text == NULL) | 612 | if (warn_text == NULL) { |
507 | warn_text = strdup(_(WARN_DUPLICATES)); | 613 | warn_text = strdup(_(WARN_DUPLICATES)); |
508 | else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) | 614 | } else if (!strstr(warn_text, _(WARN_DUPLICATES)) && |
615 | xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) { | ||
509 | die(STATE_UNKNOWN, _("Unable to realloc warn_text\n")); | 616 | die(STATE_UNKNOWN, _("Unable to realloc warn_text\n")); |
510 | return (STATE_WARNING); | 617 | } |
618 | return STATE_WARNING; | ||
511 | } | 619 | } |
512 | 620 | ||
513 | return (STATE_OK); | 621 | return STATE_OK; |
514 | } | 622 | } |
515 | 623 | ||
516 | void print_help(void) { | 624 | void print_help(void) { |
@@ -550,10 +658,10 @@ void print_help(void) { | |||
550 | printf("%s\n", _("percentage of packet loss to trigger an alarm state.")); | 658 | printf("%s\n", _("percentage of packet loss to trigger an alarm state.")); |
551 | 659 | ||
552 | printf("\n"); | 660 | printf("\n"); |
553 | printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); | 661 | printf("%s\n", |
554 | printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); | 662 | _("This plugin uses the ping command to probe the specified host for packet loss")); |
555 | printf("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in")); | 663 | printf("%s\n", |
556 | printf("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/")); | 664 | _("(percentage) and round trip average (milliseconds). It can produce HTML output.")); |
557 | 665 | ||
558 | printf(UT_SUPPORT); | 666 | printf(UT_SUPPORT); |
559 | } | 667 | } |