diff --git a/ChangeLog.d/bugfix/ZBX-19716 b/ChangeLog.d/bugfix/ZBX-19716 new file mode 100644 index 00000000000..d0c53eb456f --- /dev/null +++ b/ChangeLog.d/bugfix/ZBX-19716 @@ -0,0 +1 @@ +.......PS. [ZBX-19716] added support for response coming from different IP address than in request to ICMP checks (dimir) diff --git a/src/libs/zbxicmpping/icmpping.c b/src/libs/zbxicmpping/icmpping.c index 01586969451..2b6c19a25bb 100644 --- a/src/libs/zbxicmpping/icmpping.c +++ b/src/libs/zbxicmpping/icmpping.c @@ -277,8 +277,8 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i FILE *f; char params[70]; char filename[MAX_STRING_LEN]; - char *tmp = NULL; - size_t tmp_size; + char *linebuf = NULL; + size_t linebuf_size; size_t offset; double sec; int i, ret = NOTSUPPORTED, index, rc; @@ -310,8 +310,8 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i #endif } - tmp_size = (size_t)(MAX_STRING_LEN + count * response_time_chars_max); - tmp = zbx_malloc(tmp, tmp_size); + linebuf_size = (size_t)(MAX_STRING_LEN + count * response_time_chars_max); + linebuf = zbx_malloc(linebuf, linebuf_size); if (-1 == access(CONFIG_FPING_LOCATION, X_OK)) { @@ -480,7 +480,7 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i goto out; } - zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename); + zbx_snprintf(linebuf, linebuf_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename); } else { @@ -491,7 +491,7 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i goto out; } - zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING6_LOCATION, params6, filename); + zbx_snprintf(linebuf, linebuf_size, "%s %s 2>&1 <%s", CONFIG_FPING6_LOCATION, params6, filename); } } else @@ -508,18 +508,18 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i SUCCEED == fping_ipv6_supported ? "yes" : "no"); } - offset += zbx_snprintf(tmp + offset, tmp_size - offset, + offset += zbx_snprintf(linebuf + offset, linebuf_size - offset, "%s %s 2>&1 <%s;", CONFIG_FPING_LOCATION, params, filename); } if (0 != (fping_existence & FPING6_EXISTS) && SUCCEED != fping_ipv6_supported) { - zbx_snprintf(tmp + offset, tmp_size - offset, + zbx_snprintf(linebuf + offset, linebuf_size - offset, "%s %s 2>&1 <%s;", CONFIG_FPING6_LOCATION, params6, filename); } } #else - zbx_snprintf(tmp, tmp_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename); + zbx_snprintf(linebuf, linebuf_size, "%s %s 2>&1 <%s", CONFIG_FPING_LOCATION, params, filename); #endif /* HAVE_IPV6 */ if (NULL == (f = fopen(filename, "w"))) @@ -538,7 +538,7 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i fclose(f); - zabbix_log(LOG_LEVEL_DEBUG, "%s", tmp); + zabbix_log(LOG_LEVEL_DEBUG, "%s", linebuf); sigemptyset(&mask); sigaddset(&mask, SIGINT); @@ -547,9 +547,9 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i if (0 > sigprocmask(SIG_BLOCK, &mask, &orig_mask)) zbx_error("cannot set sigprocmask to block the user signal"); - if (NULL == (f = popen(tmp, "r"))) + if (NULL == (f = popen(linebuf, "r"))) { - zbx_snprintf(error, max_error_len, "%s: %s", tmp, zbx_strerror(errno)); + zbx_snprintf(error, max_error_len, "%s: %s", linebuf, zbx_strerror(errno)); unlink(filename); @@ -559,9 +559,9 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i goto out; } - if (NULL == zbx_fgets(tmp, (int)tmp_size, f)) + if (NULL == zbx_fgets(linebuf, (int)linebuf_size, f)) { - zbx_snprintf(tmp, tmp_size, "no output"); + zbx_snprintf(linebuf, linebuf_size, "no output"); } else { @@ -575,17 +575,40 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i { ZBX_FPING_HOST *host = NULL; char *c; + const char *linebuf_p; + + zbx_rtrim(linebuf, "\n"); + + linebuf_p = linebuf; - zbx_rtrim(tmp, "\n"); - zabbix_log(LOG_LEVEL_DEBUG, "read line [%s]", tmp); + zabbix_log(LOG_LEVEL_DEBUG, "read line \"%s\"", linebuf_p); - if (NULL != (c = strchr(tmp, ' '))) + /* When reply comes from the different IP address than the target */ + /* fping appends it in format ' [<- 10.3.0.10]'. We ignore those. */ + while (NULL != (c = strstr(linebuf_p, " [<- "))) + { + const char *p_end; + + if (NULL == (p_end = strchr(c, ']'))) + { + zabbix_log(LOG_LEVEL_DEBUG, "unexpected line sytax (expected \"]\"), ignoring"); + continue; + } + + p_end++; + + zabbix_log(LOG_LEVEL_DEBUG, "ignoring entry \"%.*s\"", (int)(p_end - c), c); + + memmove(c, p_end, strlen(p_end) + 1); /* include zero-termination character */ + } + + if (NULL != (c = strchr(linebuf_p, ' '))) { *c = '\0'; for (i = 0; i < hosts_count; i++) { - if (0 == strcmp(tmp, hosts[i].addr)) + if (0 == strcmp(linebuf_p, hosts[i].addr)) { host = &hosts[i]; break; @@ -598,32 +621,19 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i if (NULL == host) continue; - if (NULL == (c = strstr(tmp, " : "))) - continue; - /* when NIC bonding is used, there are also lines like */ /* 192.168.1.2 : duplicate for [0], 96 bytes, 0.19 ms */ - if (NULL != strstr(tmp, "duplicate for")) + if (NULL != strstr(linebuf_p, "duplicate for")) + continue; + + if (NULL == (c = strstr(linebuf_p, " : "))) continue; c += 3; - /* There were two issues with processing only the fping's final status line: */ - /* 1) pinging broadcast addresses could have resulted in responses from */ - /* different hosts, which were counted as the target host responses; */ - /* 2) there is a bug in fping (v3.8 at least) where pinging broadcast */ - /* address will result in no individual responses, but the final */ - /* status line might contain a bogus value. */ - /* Because of the above issues we must monitor the individual responses */ - /* and mark the valid ones. */ if ('[' == *c) { - /* Fping appends response source address in format '[<- 10.3.0.10]' */ - /* if it does not match the target address. Ignore such responses. */ - if (NULL != strstr(c + 1, "[<-")) - continue; - /* get the index of individual ping response */ index = atoi(c + 1); @@ -682,7 +692,7 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i #endif ret = SUCCEED; } - while (NULL != zbx_fgets(tmp, (int)tmp_size, f)); + while (NULL != zbx_fgets(linebuf, (int)linebuf_size, f)); for (i = 0; i < hosts_count; i++) zbx_free(hosts[i].status); @@ -697,9 +707,9 @@ static int process_ping(ZBX_FPING_HOST *hosts, int hosts_count, int count, int i if (WIFSIGNALED(rc)) ret = FAIL; else - zbx_snprintf(error, max_error_len, "fping failed: %s", tmp); + zbx_snprintf(error, max_error_len, "fping failed: %s", linebuf); out: - zbx_free(tmp); + zbx_free(linebuf); return ret; }