From 7deac0815afb010cce81e964fd710b8c7bcaab25 Mon Sep 17 00:00:00 2001 From: wienfuchs <44177781+wienfuchs@users.noreply.github.com> Date: Mon, 25 May 2020 18:10:10 +0200 Subject: [PATCH] changing Windows ping routine back to socket usage, leaving Linux changes made (#938) * use openssl_x509_parse to parse certinfo (avoid literal case conflict) * use OS specific ping (CLI/socket) * Moved Windows and non-Windows check to a private class Co-authored-by: TimZ99 --- src/psm/Util/Server/Updater/StatusUpdater.php | 135 ++++++++++++------ 1 file changed, 88 insertions(+), 47 deletions(-) diff --git a/src/psm/Util/Server/Updater/StatusUpdater.php b/src/psm/Util/Server/Updater/StatusUpdater.php index 8b2155dc..88f31ee6 100644 --- a/src/psm/Util/Server/Updater/StatusUpdater.php +++ b/src/psm/Util/Server/Updater/StatusUpdater.php @@ -176,55 +176,13 @@ class StatusUpdater protected function updatePing($max_runs, $run = 1) { // Settings - if ($max_runs == null || $max_runs > 1) { - $max_runs = 1; - } - $server_ip = $this->server['ip']; - $ping_command = 'ping'; - $ping_count = "-c"; + $max_runs = ($max_runs == null || $max_runs > 1) ? 1 : $max_runs; + $server_ip = escapeshellcmd($this->server['ip']); $os_is_windows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; - $result = null; - // Choose right ping version, ping6 for IPV6, ping for IPV4 - if (filter_var($server_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) { - $ping_command = $os_is_windows ? 'ping -6' : 'ping6'; - } - - // Use -n instead of -c for Windows machines - if ($os_is_windows) { - $ping_count = "-n"; - } - - // execute PING - $txt = exec($ping_command . " " . $ping_count . " " . $max_runs . " " . $server_ip . " 2>&1", $output); - - // Check if output is PING and if transmitted packets is equal to received packets. - preg_match('/^(\d{1,3}) packets transmitted, (\d{1,3}).*$/', $output[count($output) - 2], $output_package_loss); - - if ( - substr($output[0], 0, 4) == 'PING' && - !empty($output_package_loss) && - $output_package_loss[1] === $output_package_loss[2] - ) { - // Gets avg from 'round-trip min/avg/max/stddev = 7.109/7.109/7.109/0.000 ms' - preg_match_all("/(\d+\.\d+)/", $output[count($output) - 1], $result); - $result = floatval($result[0][1]); - - $this->header = ""; - foreach ($output as $key => $value) { - $this->header .= $value . "\n"; - } - $status = true; - } else { - $this->header = "-"; - foreach ($output as $key => $value) { - $this->header .= $value . "\n"; - } - $this->error = $output[count($output) - 2]; - $status = false; - } - // To miliseconds - $this->rtime = $result / 1000; + $status = $os_is_windows ? + $this->pingFromWindowsMachine($server_ip, $max_runs) : + $this->pingFromNonWindowsMachine($server_ip, $max_runs); // check if server is available and rerun if asked. if (!$status && $run < $max_runs) { @@ -466,4 +424,87 @@ class StatusUpdater $this->db->save(PSM_DB_PREFIX . 'servers', $save, array('server_id' => $this->server_id)); } } + + /** + * Ping from a Windows Machine + * @param string $server_id + * @param int $max_runs + * @return boolean + */ + private function pingFromWindowsMachine($server_ip, $max_runs) + { + // Windows / Linux variant: use socket on Windows, commandline on Linux + // socket ping - Code from http://stackoverflow.com/a/20467492 + // save response time + $starttime = microtime(true); + + // set ping payload + $package = "\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost"; + + $socket = socket_create(AF_INET, SOCK_RAW, 1); + socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 10, 'usec' => 0)); + socket_connect($socket, $server_ip, null); + socket_send($socket, $package, strLen($package), 0); + // socket_read returns a string or false + $status = socket_read($socket, 255) !== false ? true : false; + + if ($status) { + $this->header = "Success."; + } else { + $this->error = "Couldn't create socket [" . $errorcode . "]: " . socket_strerror(socket_last_error()); + } + + $this->rtime = microtime(true) - $starttime; + socket_close($socket); + + return $status; + } + + /** + * Ping from a non Windows Machine + * @param string $server_id + * @param int $max_runs + * @param string $ping_command + * @return boolean + */ + private function pingFromNonWindowsMachine($server_ip, $max_runs) + { + + // Choose right ping version, ping6 for IPV6, ping for IPV4 + $ping_command = filter_var($server_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false ? 'ping6' : 'ping'; + + // execute PING + exec($ping_command . " -c " . $max_runs . " " . $server_ip . " 2>&1", $output); + + // Check if output is PING and if transmitted packets is equal to received packets. + preg_match( + '/^(\d{1,3}) packets transmitted, (\d{1,3}).*$/', + $output[count($output) - 2], + $output_package_loss + ); + + if ( + substr($output[0], 0, 4) == 'PING' && + !empty($output_package_loss) && + $output_package_loss[1] === $output_package_loss[2] + ) { + // Gets avg from 'round-trip min/avg/max/stddev = 7.109/7.109/7.109/0.000 ms' + preg_match_all("/(\d+\.\d+)/", $output[count($output) - 1], $result); + // Converted to milliseconds + $this->rtime = floatval($result[0][1]) / 1000; + + $this->header = ""; + foreach ($output as $key => $value) { + $this->header .= $value . "\n"; + } + return true; + } + + $this->header = "-"; + foreach ($output as $key => $value) { + $this->header .= $value . "\n"; + } + $this->error = $output[count($output) - 2]; + return false; + } }