Closed MSS970 closed 6 months ago
That's a good catch. Found some inconsistent use elsewhere too. Not material like lib/ping.php
though.
Hi TheWitness, I use CACTI dev 1.3.
Furthermore, I don't see any ' ms' in the output of fping as stated in the ping.php, hence my previous suggestion requires fine tuning be removing the part related to ' ms'.
Regards,
So, it needs some more tuning. Just for Windows right?
Yes, that's right
Can you drop the output from doing here?
Hi TheWitness,
It seems you have omitted the complete part related to Windows native "ping" if it is in use.
For Windows OS, the native "ping" command is available and could be used if "fping" is NOT installed, however, if the "fping" is installed on Windows then I will recommend to leave the native "ping" works.
The below can be considered as the solution:
function ping_icmp() {
global $config;
/* ping me */
if ($this->host['hostname']) {
/* initialize variables */
$this->ping_status = 'down';
$this->ping_response = __('ICMP Ping timed out');
/* establish timeout variables */
$to_sec = floor($this->timeout / 1000);
$to_usec = ($this->timeout % 1000) * 1000;
/* clean up hostname if specifying snmp_transport */
$this->host['hostname'] = $this->strip_ip_address($this->host['hostname']);
/* determine the host's ip address
* this prevents from command injection as well*/
if ($this->is_ipaddress($this->host['hostname'])) {
$host_ip = $this->host['hostname'];
} else {
/* again, as a side effect, prevention from command injection */
$host_ip = cacti_gethostbyname($this->host['hostname']);
if (!$this->is_ipaddress($host_ip)) {
cacti_log('WARNING: ICMP Ping Error: cacti_gethostbyname failed for ' . $this->host['hostname']);
$this->response = 'ICMP Ping Error: cacti_gethostbyname failed for ' . $this->host['hostname'];
return false;
}
}
/* we have to use the real ping, in cases where windows failed or while using UNIX/Linux */
$pattern = bin2hex('cacti-monitoring-system'); // the actual test data
$fping = read_config_option('path_fping');
if ($fping != '' && file_exists($fping) && is_executable($fping)) {
if (strpos($this->host['hostname'], ':') !== false) {
$result = shell_exec('/usr/sbin/fping6 -q -t ' . $this->timeout . ' -c 1 -r ' . $this->retries . ' ' . $this->host['hostname'] . ' 2>&1');
} else {
$result = shell_exec($fping . ' -q -t ' . $this->timeout . ' -c 1 -r ' . $this->retries . ' ' . $this->host['hostname'] . ' 2>&1');
}
} else {
/* host timeout given in ms, recalculate to sec, but make it an integer
* we might consider to use escapeshellarg on hostname,
* but this field has already been verified.
* The other fields are numerical fields only and thus
* not vulnerable for command injection */
if (substr_count(strtolower(PHP_OS), 'sun')) {
$result = shell_exec('ping ' . $this->host['hostname']);
} elseif (substr_count(strtolower(PHP_OS), 'hpux')) {
$result = shell_exec('ping -m ' . ceil($this->timeout / 1000) . ' -n ' . $this->retries . ' ' . $this->host['hostname']);
} elseif (substr_count(strtolower(PHP_OS), 'mac')) {
$result = shell_exec('ping -t ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' ' . $this->host['hostname']);
} elseif (substr_count(strtolower(PHP_OS), 'freebsd')) {
if (strpos($this->host['hostname'], ':') !== false) {
$result = shell_exec('ping6 -X ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' ' . $this->host['hostname']);
} else {
$result = shell_exec('ping -t ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' ' . $this->host['hostname']);
}
} elseif (substr_count(strtolower(PHP_OS), 'darwin')) {
$result = shell_exec('ping -t ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' ' . $this->host['hostname']);
} elseif (substr_count(strtolower(PHP_OS), 'bsd')) {
$result = shell_exec('ping -w ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' ' . $this->host['hostname']);
} elseif (substr_count(strtolower(PHP_OS), 'aix')) {
$result = shell_exec('ping -i ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' ' . $this->host['hostname']);
} elseif (substr_count(strtolower(PHP_OS), 'winnt')) {
$result = shell_exec('chcp 437 && ping -w ' . $this->timeout . ' -n ' . $this->retries . ' ' . $this->host['hostname']);
} else {
/* please know, that when running SELinux, httpd will throw
* ping: cap_set_proc: Permission denied
* as it now tries to open an ICMP socket and fails
* $result will be empty, then. */
if (strpos($host_ip, ':') !== false) {
$result = shell_exec('ping6 -W ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' -p ' . $pattern . ' ' . $this->host['hostname']);
} else {
$result = shell_exec('ping -W ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' -p ' . $pattern . ' ' . $this->host['hostname'] . ' 2>&1');
if ((strpos($result, 'unknown host') !== false || strpos($result, 'Address family') !== false) && file_exists('/bin/ping6')) {
$result = shell_exec('ping6 -W ' . ceil($this->timeout / 1000) . ' -c ' . $this->retries . ' -p ' . $pattern . ' ' . $this->host['hostname']);
}
}
}
}
if (strtolower(PHP_OS) != 'winnt') {
$position = strpos($result, 'min/avg/max');
if ($position > 0) {
$output = trim(str_replace(' ms', '', substr($result, $position)));
$pieces = explode('=', $output);
$results = explode('/', $pieces[1]);
$this->ping_status = $results[1];
$this->ping_response = __('ICMP Ping Success (%s ms)', $results[1]);
return true;
} else {
$this->status = 'down';
$this->ping_response = __('ICMP ping Timed out');
return false;
}
} else {
// -- START - Modified by MSS on 2024-01-15
// ----------------------------------------
// in case of strtolower(PHP_OS) = 'winnt'
if ($fping != '' && file_exists($fping) && is_executable($fping)) {
// in case fping is used in Windows
// $results would look like:
// 172.31.112.2 : xmt/rcv/%loss = 1/1/0%, min/avg/max = 7.01/7.01/7.01
$position = strpos($result, 'min/avg/max');
if ($position > 0) {
$output = substr($result, $position);
$pieces = explode('=', $output);
$results = explode('/', $pieces[1]);
$this->ping_status = $results[1];
$this->ping_response = __('ICMP Ping Success (%s ms)', $results[1]);
return true;
} else {
$this->status = 'down';
$this->ping_response = __('ICMP ping Timed out (' . $this->host['hostname'] . '), Result [' . $result . ']');
return false;
}
} else {
// in case native ping is used in Windows
// the ping result would look like:
/*
ping -w 500 -n 3 www.google.com
Pinging forcesafesearch.google.com [216.239.38.120] with 32 bytes of data:
Reply from 216.239.38.120: bytes=32 time=30ms TTL=53
Reply from 216.239.38.120: bytes=32 time=22ms TTL=53
Reply from 216.239.38.120: bytes=32 time=25ms TTL=53
Ping statistics for 216.239.38.120:
Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 22ms, Maximum = 30ms, Average = 25ms
*/
$position = strpos($result, 'Minimum');
if ($position > 0) {
$output = trim(substr($result, $position));
// $output will be:
// Minimum = 22ms, Maximum = 30ms, Average = 25ms
$pieces = explode(',', $output);
$results = explode('=', $pieces[2]);
$this->ping_status = trim(str_replace('ms', '', $results[1]));
$this->ping_response = __('ICMP Ping Success (%s ms)', $this->ping_status);
return true;
} else {
$this->status = 'down';
$this->ping_response = __('ICMP ping Timed out (' . $this->host['hostname'] . '), Result [' . $result . ']');
return false;
}
}
// -- END - Modified by MSS on 2024-01-15
// ------------------------------------
}
} else {
$this->ping_status = 'down';
$this->ping_response = __('Destination address not specified');
return false;
}
}
Let me know if this is ok.
I'll take a look this week. Post here again once I verify.
A pull request would be better...
Hi There, If fping is installed in Windows, fping would rung, but the results are check/validated against the logic of Windows ping.
https://github.com/Cacti/cacti/blob/4563aaa1db7cc90f44edb25b23698a1d0208139e/lib/ping.php#L243
I suggest to change the code in ping.php starting from line #243 to the following: