1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "zbxicmpping.h"
21 #include "threads.h"
22 #include "comms.h"
23 #include "zbxexec.h"
24 #include "log.h"
25 #include <signal.h>
26
27 extern char *CONFIG_SOURCE_IP;
28 extern char *CONFIG_FPING_LOCATION;
29 #ifdef HAVE_IPV6
30 extern char *CONFIG_FPING6_LOCATION;
31 #endif
32 extern char *CONFIG_TMPDIR;
33
34 /* old official fping (2.4b2_to_ipv6) did not support source IP address */
35 /* old patched versions (2.4b2_to_ipv6) provided either -I or -S options */
36 /* since fping 3.x it provides -I option for binding to an interface and -S option for source IP address */
37
38 static unsigned char source_ip_checked;
39 static const char *source_ip_option;
40 #ifdef HAVE_IPV6
41 static unsigned char source_ip6_checked;
42 static const char *source_ip6_option;
43 #endif
44
45 #define FPING_UNINITIALIZED_VALUE -2
46 static int packet_interval;
47 #ifdef HAVE_IPV6
48 static int packet_interval6;
49 static int fping_ipv6_supported;
50 #endif
51
52 #define FPING_CHECK_EXPIRED 3600 /* seconds, expire detected fping options every hour */
53 static time_t fping_check_reset_at; /* time of the last fping options expiration */
54
get_source_ip_option(const char * fping,const char ** option,unsigned char * checked)55 static void get_source_ip_option(const char *fping, const char **option, unsigned char *checked)
56 {
57 FILE *f;
58 char *p, tmp[MAX_STRING_LEN];
59
60 zbx_snprintf(tmp, sizeof(tmp), "%s -h 2>&1", fping);
61
62 if (NULL == (f = popen(tmp, "r")))
63 return;
64
65 while (NULL != zbx_fgets(tmp, sizeof(tmp), f))
66 {
67 for (p = tmp; isspace(*p); p++)
68 ;
69
70 if ('-' == p[0] && 'I' == p[1] && (isspace(p[2]) || ',' == p[2]))
71 {
72 *option = "-I";
73 continue;
74 }
75
76 if ('-' == p[0] && 'S' == p[1] && (isspace(p[2]) || ',' == p[2]))
77 {
78 *option = "-S";
79 break;
80 }
81 }
82
83 pclose(f);
84
85 *checked = 1;
86 }
87
88 /******************************************************************************
89 * *
90 * Function: get_interval_option *
91 * *
92 * Purpose: detect minimal possible fping packet interval *
93 * *
94 * Parameters: fping - [IN] the location of fping program *
95 * dst - [IN] the ip address for test *
96 * value - [OUT] interval between sending ping packets *
97 * (in millisec) *
98 * error - [OUT] error string if function fails *
99 * max_error_len - [IN] length of error buffer *
100 * *
101 * Return value: SUCCEED if processed successfully or FAIL otherwise *
102 * *
103 * Comments: supported minimum interval (in milliseconds) in different fping *
104 * versions: *
105 * +------------------+--------------------------+---------+ *
106 * | version X | as root/non-root/without | Default | *
107 * | | "safe limits" | | *
108 * +------------------+--------------------------+---------+ *
109 * | X < 3.14 | 1 / 10 / - | 25 | *
110 * | 3.14 <= X < 4.0 | 0 / 1 / - | 25 | *
111 * | 4.0 <= X | 0 / 0 / 1 | 10 | *
112 * +------------------+--------------------------+---------+ *
113 * Note! "Safe limits" is compile-time option introduced in *
114 * fping 4.0. Distribution packages ship fping binary without *
115 * "safe limits". *
116 * *
117 ******************************************************************************/
get_interval_option(const char * fping,const char * dst,int * value,char * error,size_t max_error_len)118 static int get_interval_option(const char *fping, const char *dst, int *value, char *error, size_t max_error_len)
119 {
120 char *out = NULL;
121 unsigned int intervals[] = {0, 1, 10};
122 size_t i, out_len;
123 int ret = FAIL;
124
125 for (i = 0; i < ARRSIZE(intervals); i++)
126 {
127 int ret_exec;
128 char tmp[MAX_STRING_LEN], err[255];
129 const char *p;
130
131 zabbix_log(LOG_LEVEL_DEBUG, "testing fping interval %u ms", intervals[i]);
132
133 zbx_snprintf(tmp, sizeof(tmp), "%s -c1 -t50 -i%u %s", fping, intervals[i], dst);
134
135 zbx_free(out);
136
137 /* call fping, ignore its exit code but mind execution failures */
138 if (TIMEOUT_ERROR == (ret_exec = zbx_execute(tmp, &out, err, sizeof(err), 1,
139 ZBX_EXIT_CODE_CHECKS_DISABLED)))
140 {
141 zbx_snprintf(error, max_error_len, "Timeout while executing \"%s\"", tmp);
142 goto out;
143 }
144
145 if (FAIL == ret_exec)
146 {
147 zbx_snprintf(error, max_error_len, "Cannot execute \"%s\": %s", tmp, err);
148 goto out;
149 }
150
151 /* First, check the output for suggested interval option, e. g.: */
152 /* */
153 /* /usr/sbin/fping: these options are too risky for mere mortals. */
154 /* /usr/sbin/fping: You need i >= 1, p >= 20, r < 20, and t >= 50 */
155
156 #define FPING_YOU_NEED_PREFIX "You need i >= "
157
158 if (NULL != (p = strstr(out, FPING_YOU_NEED_PREFIX)))
159 {
160 p += ZBX_CONST_STRLEN(FPING_YOU_NEED_PREFIX);
161
162 *value = atoi(p);
163 ret = SUCCEED;
164
165 goto out;
166 }
167
168 #undef FPING_YOU_NEED_PREFIX
169
170 /* in fping 3.16 they changed "You need i >=" to "You need -i >=" */
171
172 #define FPING_YOU_NEED_PREFIX "You need -i >= "
173
174 if (NULL != (p = strstr(out, FPING_YOU_NEED_PREFIX)))
175 {
176 p += ZBX_CONST_STRLEN(FPING_YOU_NEED_PREFIX);
177
178 *value = atoi(p);
179 ret = SUCCEED;
180
181 goto out;
182 }
183
184 #undef FPING_YOU_NEED_PREFIX
185
186 /* if we get dst in the beginning of the output, the used interval is allowed, */
187 /* unless we hit the help message which is always bigger than 1 Kb */
188 if (ZBX_KIBIBYTE > strlen(out))
189 {
190 /* skip white spaces */
191 for (p = out; '\0' != *p && isspace(*p); p++)
192 ;
193
194 if (strlen(p) >= strlen(dst) && 0 == strncmp(p, dst, strlen(dst)))
195 {
196 *value = intervals[i];
197 ret = SUCCEED;
198
199 goto out;
200 }
201
202 /* check if we hit the error message */
203 if (NULL != strstr(out, " as root"))
204 {
205 zbx_rtrim(out, "\n");
206 zbx_strlcpy(error, out, max_error_len);
207 goto out;
208 }
209 }
210 }
211
212 /* if we are here we have probably hit the usage or error message, let's collect it if it's error message */
213
214 if (NULL != out && ZBX_KIBIBYTE > (out_len = strlen(out)) && 0 != out_len)
215 {
216 zbx_rtrim(out, "\n");
217 zbx_strlcpy(error, out, max_error_len);
218 }
219 else
220 zbx_snprintf(error, max_error_len, "Cannot detect the minimum interval of %s", fping);
221 out:
222 zbx_free(out);
223
224 return ret;
225 }
226
227 #ifdef HAVE_IPV6
228 /******************************************************************************
229 * *
230 * Function: get_ipv6_support *
231 * *
232 * Purpose: check fping supports IPv6 *
233 * *
234 * Parameters: fping - [IN] the location of fping program *
235 * dst - [IN] the ip address for test *
236 * *
237 * Return value: SUCCEED - IPv6 is supported *
238 * FAIL - IPv6 is not supported *
239 * *
240 ******************************************************************************/
get_ipv6_support(const char * fping,const char * dst)241 static int get_ipv6_support(const char * fping, const char *dst)
242 {
243 int ret;
244 char tmp[MAX_STRING_LEN], error[255], *out = NULL;
245
246 zbx_snprintf(tmp, sizeof(tmp), "%s -6 -c1 -t50 %s", fping, dst);
247
248 if ((SUCCEED == (ret = zbx_execute(tmp, &out, error, sizeof(error), 1, ZBX_EXIT_CODE_CHECKS_DISABLED)) &&
249 ZBX_KIBIBYTE > strlen(out) && NULL != strstr(out, dst)) || TIMEOUT_ERROR == ret)
250 {
251 ret = SUCCEED;
252 }
253 else
254 {
255 ret = FAIL;
256 }
257
258 zbx_free(out);
259
260 return ret;
261
262 }
263 #endif /* HAVE_IPV6 */
264
process_ping(ZBX_FPING_HOST * hosts,int hosts_count,int count,int interval,int size,int timeout,char * error,size_t max_error_len)265 static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int interval, int size, int timeout,
266 char *error, size_t max_error_len)
267 {
268 const int response_time_chars_max = 20;
269 FILE *f;
270 char params[70];
271 char filename[MAX_STRING_LEN];
272 char *tmp = NULL;
273 size_t tmp_size;
274 size_t offset;
275 double sec;
276 int i, ret = NOTSUPPORTED, index, rc;
277 sigset_t mask, orig_mask;
278
279 #ifdef HAVE_IPV6
280 int family;
281 char params6[70];
282 size_t offset6;
283 char fping_existence = 0;
284 #define FPING_EXISTS 0x1
285 #define FPING6_EXISTS 0x2
286
287 #endif /* HAVE_IPV6 */
288
289 assert(hosts);
290
291 /* expire detected options once in a while */
292 if ((time(NULL) - fping_check_reset_at) > FPING_CHECK_EXPIRED)
293 {
294 fping_check_reset_at = time(NULL);
295
296 source_ip_checked = 0;
297 packet_interval = FPING_UNINITIALIZED_VALUE;
298 #ifdef HAVE_IPV6
299 source_ip6_checked = 0;
300 packet_interval6 = FPING_UNINITIALIZED_VALUE;
301 fping_ipv6_supported = FPING_UNINITIALIZED_VALUE;
302 #endif
303 }
304
305 tmp_size = (size_t)(MAX_STRING_LEN + count * response_time_chars_max);
306 tmp = zbx_malloc(tmp, tmp_size);
307
308 if (-1 == access(CONFIG_FPING_LOCATION, X_OK))
309 {
310 #if !defined(HAVE_IPV6)
311 zbx_snprintf(error, max_error_len, "%s: %s", CONFIG_FPING_LOCATION, zbx_strerror(errno));
312 goto out;
313 #endif
314 }
315 else
316 {
317 #ifdef HAVE_IPV6
318 fping_existence |= FPING_EXISTS;
319 #else
320 if (NULL != CONFIG_SOURCE_IP)
321 {
322 if (FAIL == is_ip4(CONFIG_SOURCE_IP)) /* we do not have IPv4 family address in CONFIG_SOURCE_IP */
323 {
324 zbx_snprintf(error, max_error_len,
325 "You should enable IPv6 support to use IPv6 family address for SourceIP '%s'.", CONFIG_SOURCE_IP);
326 goto out;
327 }
328 }
329 #endif
330 }
331
332 #ifdef HAVE_IPV6
333 if (-1 == access(CONFIG_FPING6_LOCATION, X_OK))
334 {
335 if (0 == (fping_existence & FPING_EXISTS))
336 {
337 zbx_snprintf(error, max_error_len, "At least one of '%s', '%s' must exist. Both are missing in the system.",
338 CONFIG_FPING_LOCATION,
339 CONFIG_FPING6_LOCATION);
340 goto out;
341 }
342 }
343 else
344 fping_existence |= FPING6_EXISTS;
345 #endif /* HAVE_IPV6 */
346
347 offset = zbx_snprintf(params, sizeof(params), "-C%d", count);
348 if (0 != interval)
349 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -p%d", interval);
350 if (0 != size)
351 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -b%d", size);
352 if (0 != timeout)
353 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -t%d", timeout);
354
355 #ifdef HAVE_IPV6
356 strscpy(params6, params);
357 offset6 = offset;
358
359 if (0 != (fping_existence & FPING_EXISTS) && 0 != hosts_count)
360 {
361 if (FPING_UNINITIALIZED_VALUE == packet_interval)
362 {
363 if (SUCCEED != get_interval_option(CONFIG_FPING_LOCATION, hosts[0].addr, &packet_interval,
364 error, max_error_len))
365 {
366 goto out;
367 }
368
369 zabbix_log(LOG_LEVEL_DEBUG, "detected minimum supported fping interval (-i): %d",
370 packet_interval);
371 }
372
373 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -i%d", packet_interval);
374 }
375
376 if (0 != (fping_existence & FPING6_EXISTS) && 0 != hosts_count)
377 {
378 if (FPING_UNINITIALIZED_VALUE == packet_interval6)
379 {
380 if (SUCCEED != get_interval_option(CONFIG_FPING6_LOCATION, hosts[0].addr, &packet_interval6,
381 error, max_error_len))
382 {
383 goto out;
384 }
385
386 zabbix_log(LOG_LEVEL_DEBUG, "detected minimum supported fping6 interval (-i): %d",
387 packet_interval6);
388 }
389
390 offset6 += zbx_snprintf(params6 + offset6, sizeof(params6) - offset6, " -i%d", packet_interval6);
391 }
392 #else
393 if (0 != hosts_count)
394 {
395 if (FPING_UNINITIALIZED_VALUE == packet_interval)
396 {
397 if (SUCCEED != get_interval_option(CONFIG_FPING_LOCATION, hosts[0].addr, &packet_interval,
398 error, max_error_len))
399 {
400 goto out;
401 }
402
403 zabbix_log(LOG_LEVEL_DEBUG, "detected minimum supported fping interval (-i): %d",
404 packet_interval);
405 }
406
407 offset += zbx_snprintf(params + offset, sizeof(params) - offset, " -i%d", packet_interval);
408 }
409 #endif /* HAVE_IPV6 */
410
411 if (NULL != CONFIG_SOURCE_IP)
412 {
413 #ifdef HAVE_IPV6
414 if (0 != (fping_existence & FPING_EXISTS))
415 {
416 if (0 == source_ip_checked)
417 {
418 get_source_ip_option(CONFIG_FPING_LOCATION, &source_ip_option, &source_ip_checked);
419
420 zabbix_log(LOG_LEVEL_DEBUG, "detected fping source IP option: \"%s\"",
421 ZBX_NULL2EMPTY_STR(source_ip_option));
422 }
423
424 if (NULL != source_ip_option)
425 zbx_snprintf(params + offset, sizeof(params) - offset,
426 " %s%s", source_ip_option, CONFIG_SOURCE_IP);
427 }
428
429 if (0 != (fping_existence & FPING6_EXISTS))
430 {
431 if (0 == source_ip6_checked)
432 {
433 get_source_ip_option(CONFIG_FPING6_LOCATION, &source_ip6_option, &source_ip6_checked);
434
435 zabbix_log(LOG_LEVEL_DEBUG, "detected fping6 source IP option: \"%s\"",
436 ZBX_NULL2EMPTY_STR(source_ip6_option));
437 }
438
439 if (NULL != source_ip6_option)
440 zbx_snprintf(params6 + offset6, sizeof(params6) - offset6,
441 " %s%s", source_ip6_option, CONFIG_SOURCE_IP);
442 }
443 #else
444 if (0 == source_ip_checked)
445 {
446 get_source_ip_option(CONFIG_FPING_LOCATION, &source_ip_option, &source_ip_checked);
447
448 zabbix_log(LOG_LEVEL_DEBUG, "detected fping source IP option: \"%s\"",
449 ZBX_NULL2EMPTY_STR(source_ip_option));
450 }
451
452 if (NULL != source_ip_option)
453 zbx_snprintf(params + offset, sizeof(params) - offset,
454 " %s%s", source_ip_option, CONFIG_SOURCE_IP);
455 #endif /* HAVE_IPV6 */
456 }
457
458 zbx_snprintf(filename, sizeof(filename), "%s/%s_%li.pinger", CONFIG_TMPDIR, progname, zbx_get_thread_id());
459
460 #ifdef HAVE_IPV6
461 if (NULL != CONFIG_SOURCE_IP)
462 {
463 if (SUCCEED != get_address_family(CONFIG_SOURCE_IP, &family, error, (int)max_error_len))
464 goto out;
465
466 if (family == PF_INET)
467 {
468 if (0 == (fping_existence & FPING_EXISTS))
469 {
470 zbx_snprintf(error, max_error_len, "File '%s' cannot be found in the system.",
471 CONFIG_FPING_LOCATION);
472 goto out;
473 }
474
475 zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename);
476 }
477 else
478 {
479 if (0 == (fping_existence & FPING6_EXISTS))
480 {
481 zbx_snprintf(error, max_error_len, "File '%s' cannot be found in the system.",
482 CONFIG_FPING6_LOCATION);
483 goto out;
484 }
485
486 zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING6_LOCATION, params6, filename);
487 }
488 }
489 else
490 {
491 offset = 0;
492
493 if (0 != (fping_existence & FPING_EXISTS))
494 {
495 if (FPING_UNINITIALIZED_VALUE == fping_ipv6_supported)
496 {
497 fping_ipv6_supported = get_ipv6_support(CONFIG_FPING_LOCATION,hosts[0].addr);
498
499 zabbix_log(LOG_LEVEL_DEBUG, "detected fping IPv6 support: \"%s\"",
500 SUCCEED == fping_ipv6_supported ? "yes" : "no");
501 }
502
503 offset += zbx_snprintf(tmp + offset, tmp_size - offset,
504 "%s %s 2>&1 <%s;", CONFIG_FPING_LOCATION, params, filename);
505 }
506
507 if (0 != (fping_existence & FPING6_EXISTS) && SUCCEED != fping_ipv6_supported)
508 {
509 zbx_snprintf(tmp + offset, tmp_size - offset,
510 "%s %s 2>&1 <%s;", CONFIG_FPING6_LOCATION, params6, filename);
511 }
512 }
513 #else
514 zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename);
515 #endif /* HAVE_IPV6 */
516
517 if (NULL == (f = fopen(filename, "w")))
518 {
519 zbx_snprintf(error, max_error_len, "%s: %s", filename, zbx_strerror(errno));
520 goto out;
521 }
522
523 zabbix_log(LOG_LEVEL_DEBUG, "%s", filename);
524
525 for (i = 0; i < hosts_count; i++)
526 {
527 zabbix_log(LOG_LEVEL_DEBUG, " %s", hosts[i].addr);
528 fprintf(f, "%s\n", hosts[i].addr);
529 }
530
531 fclose(f);
532
533 zabbix_log(LOG_LEVEL_DEBUG, "%s", tmp);
534
535 sigemptyset(&mask);
536 sigaddset(&mask, SIGINT);
537 sigaddset(&mask, SIGQUIT);
538
539 if (0 > sigprocmask(SIG_BLOCK, &mask, &orig_mask))
540 zbx_error("cannot set sigprocmask to block the user signal");
541
542 if (NULL == (f = popen(tmp, "r")))
543 {
544 zbx_snprintf(error, max_error_len, "%s: %s", tmp, zbx_strerror(errno));
545
546 unlink(filename);
547
548 if (0 > sigprocmask(SIG_SETMASK, &orig_mask, NULL))
549 zbx_error("cannot restore sigprocmask");
550
551 goto out;
552 }
553
554 if (NULL == zbx_fgets(tmp, (int)tmp_size, f))
555 {
556 zbx_snprintf(tmp, tmp_size, "no output");
557 }
558 else
559 {
560 for (i = 0; i < hosts_count; i++)
561 {
562 hosts[i].status = (char *)zbx_malloc(NULL, (size_t)count);
563 memset(hosts[i].status, 0, (size_t)count);
564 }
565
566 do
567 {
568 ZBX_FPING_HOST *host = NULL;
569 char *c;
570
571 zbx_rtrim(tmp, "\n");
572 zabbix_log(LOG_LEVEL_DEBUG, "read line [%s]", tmp);
573
574 if (NULL != (c = strchr(tmp, ' ')))
575 {
576 *c = '\0';
577
578 for (i = 0; i < hosts_count; i++)
579 {
580 if (0 == strcmp(tmp, hosts[i].addr))
581 {
582 host = &hosts[i];
583 break;
584 }
585 }
586
587 *c = ' ';
588 }
589
590 if (NULL == host)
591 continue;
592
593 if (NULL == (c = strstr(tmp, " : ")))
594 continue;
595
596 /* when NIC bonding is used, there are also lines like */
597 /* 192.168.1.2 : duplicate for [0], 96 bytes, 0.19 ms */
598
599 if (NULL != strstr(tmp, "duplicate for"))
600 continue;
601
602 c += 3;
603
604 /* There were two issues with processing only the fping's final status line: */
605 /* 1) pinging broadcast addresses could have resulted in responses from */
606 /* different hosts, which were counted as the target host responses; */
607 /* 2) there is a bug in fping (v3.8 at least) where pinging broadcast */
608 /* address will result in no individual responses, but the final */
609 /* status line might contain a bogus value. */
610 /* Because of the above issues we must monitor the individual responses */
611 /* and mark the valid ones. */
612 if ('[' == *c)
613 {
614 /* Fping appends response source address in format '[<- 10.3.0.10]' */
615 /* if it does not match the target address. Ignore such responses. */
616 if (NULL != strstr(c + 1, "[<-"))
617 continue;
618
619 /* get the index of individual ping response */
620 index = atoi(c + 1);
621
622 if (0 > index || index >= count)
623 continue;
624
625 /* since 5.0 Fping outputs individual failed packages in additional to successful: */
626 /* */
627 /* fping -C3 -i0 7.7.7.7 8.8.8.8 */
628 /* 8.8.8.8 : [0], 64 bytes, 9.37 ms (9.37 avg, 0% loss) */
629 /* 7.7.7.7 : [0], timed out (NaN avg, 100% loss) */
630 /* 8.8.8.8 : [1], 64 bytes, 8.72 ms (9.05 avg, 0% loss) */
631 /* 7.7.7.7 : [1], timed out (NaN avg, 100% loss) */
632 /* 8.8.8.8 : [2], 64 bytes, 7.28 ms (8.46 avg, 0% loss) */
633 /* 7.7.7.7 : [2], timed out (NaN avg, 100% loss) */
634 /* */
635 /* 7.7.7.7 : - - - */
636 /* 8.8.8.8 : 9.37 8.72 7.28 */
637 /* */
638 /* Judging by Fping source code we can disregard lines reporting "timed out". */
639
640 if (NULL != strstr(c + 2, " timed out "))
641 continue;
642
643 host->status[index] = 1;
644
645 continue;
646 }
647
648 /* process status line for a host */
649 index = 0;
650 do
651 {
652 if (1 == host->status[index])
653 {
654 sec = atof(c) / 1000; /* convert ms to seconds */
655
656 if (0 == host->rcv || host->min > sec)
657 host->min = sec;
658 if (0 == host->rcv || host->max < sec)
659 host->max = sec;
660 host->sum += sec;
661 host->rcv++;
662 }
663 }
664 while (++index < count && NULL != (c = strchr(c + 1, ' ')));
665
666 host->cnt += count;
667 #ifdef HAVE_IPV6
668 if (host->cnt == count && NULL == CONFIG_SOURCE_IP &&
669 0 != (fping_existence & FPING_EXISTS) &&
670 0 != (fping_existence & FPING6_EXISTS))
671 {
672 memset(host->status, 0, (size_t)count); /* reset response statuses for IPv6 */
673 }
674 #endif
675 ret = SUCCEED;
676 }
677 while (NULL != zbx_fgets(tmp, (int)tmp_size, f));
678
679 for (i = 0; i < hosts_count; i++)
680 zbx_free(hosts[i].status);
681 }
682 rc = pclose(f);
683
684 if (0 > sigprocmask(SIG_SETMASK, &orig_mask, NULL))
685 zbx_error("cannot restore sigprocmask");
686
687 unlink(filename);
688
689 if (WIFSIGNALED(rc))
690 ret = FAIL;
691 else
692 zbx_snprintf(error, max_error_len, "fping failed: %s", tmp);
693 out:
694 zbx_free(tmp);
695
696 return ret;
697 }
698
699 /******************************************************************************
700 * *
701 * Function: zbx_ping *
702 * *
703 * Purpose: ping hosts listed in the host files *
704 * *
705 * hosts_count - [IN] number of target hosts *
706 * count - [IN] number of pings to send to each target *
707 * (fping option -C) *
708 * period - [IN] interval between ping packets to one *
709 * target, in milliseconds *
710 * (fping option -p) *
711 * size - [IN] amount of ping data to send, in bytes *
712 * (fping option -b) *
713 * timeout - [IN] individual target initial timeout except *
714 * when count > 1, where it's the -p period *
715 * (fping option -t) *
716 * error - [OUT] error string if function fails *
717 * max_error_len - [IN] length of error buffer *
718 * *
719 * Return value: SUCCEED - successfully processed hosts *
720 * NOTSUPPORTED - otherwise *
721 * *
722 * Author: Alexei Vladishev *
723 * *
724 * Comments: use external binary 'fping' to avoid superuser privileges *
725 * *
726 ******************************************************************************/
zbx_ping(ZBX_FPING_HOST * hosts,int hosts_count,int count,int period,int size,int timeout,char * error,size_t max_error_len)727 int zbx_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int period, int size, int timeout,
728 char *error, size_t max_error_len)
729 {
730 int ret;
731
732 zabbix_log(LOG_LEVEL_DEBUG, "In %s() hosts_count:%d", __func__, hosts_count);
733
734 if (NOTSUPPORTED == (ret = process_ping(hosts, hosts_count, count, period, size, timeout, error, max_error_len)))
735 zabbix_log(LOG_LEVEL_ERR, "%s", error);
736
737 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
738
739 return ret;
740 }
741