From 194e64244824eee9fd37fc8fa0605fef26f951ba Mon Sep 17 00:00:00 2001 From: terrafrost Date: Tue, 15 Dec 2020 08:25:42 -0600 Subject: [PATCH] SSH2: handle keepalive@openssh.com packets --- phpseclib/Net/SSH2.php | 112 +++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 50 deletions(-) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 17125801..ce007b06 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -3351,6 +3351,57 @@ class Net_SSH2 */ function _get_binary_packet($skip_channel_filter = false) { + if ($skip_channel_filter) { + $read = array($this->fsock); + $write = $except = null; + + if ($this->curTimeout <= 0) { + if ($this->keepAlive <= 0) { + @stream_select($read, $write, $except, null); + } else { + if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) { + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0)); + return $this->_get_binary_packet(true); + } + } + } else { + if ($this->curTimeout < 0) { + $this->is_timeout = true; + return true; + } + + $read = array($this->fsock); + $write = $except = null; + + $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 + + if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) { + if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) { + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0)); + $elapsed = strtok(microtime(), ' ') + strtok('') - $start; + $this->curTimeout-= $elapsed; + return $this->_get_binary_packet(true); + } + $elapsed = strtok(microtime(), ' ') + strtok('') - $start; + $this->curTimeout-= $elapsed; + } + + $sec = floor($this->curTimeout); + $usec = 1000000 * ($this->curTimeout - $sec); + + // on windows this returns a "Warning: Invalid CRT parameters detected" error + if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { + $this->is_timeout = true; + if ($client_channel == NET_SSH2_CHANNEL_EXEC && !$this->request_pty) { + $this->_close_channel($client_channel); + } + return true; + } + $elapsed = strtok(microtime(), ' ') + strtok('') - $start; + $this->curTimeout-= $elapsed; + } + } + if (!is_resource($this->fsock) || feof($this->fsock)) { $this->bitmap = 0; user_error('Connection closed prematurely'); @@ -3502,9 +3553,19 @@ class Net_SSH2 // only called when we've already logged in if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && $this->isAuthenticated()) { switch (ord($payload[0])) { + case NET_SSH2_MSG_CHANNEL_REQUEST: + if (strlen($payload) == 31) { + extract(unpack('cpacket_type/Nchannel/Nlength', $payload)); + if (substr($payload, 9, $length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) { + if (ord(substr($payload, 9 + $length))) { // want reply + $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_SUCCESS, $this->server_channels[$channel])); + } + $payload = $this->_get_binary_packet($skip_channel_filter); + } + } + break; case NET_SSH2_MSG_CHANNEL_DATA: case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: - case NET_SSH2_MSG_CHANNEL_REQUEST: case NET_SSH2_MSG_CHANNEL_CLOSE: case NET_SSH2_MSG_CHANNEL_EOF: if (!$skip_channel_filter && !empty($this->server_channels)) { @@ -3702,55 +3763,6 @@ class Net_SSH2 $response = $this->binary_packet_buffer; $this->binary_packet_buffer = false; } else { - $read = array($this->fsock); - $write = $except = null; - - if ($this->curTimeout <= 0) { - if ($this->keepAlive <= 0) { - @stream_select($read, $write, $except, null); - } else { - if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) { - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0)); - continue; - } - } - } else { - if ($this->curTimeout < 0) { - $this->is_timeout = true; - return true; - } - - $read = array($this->fsock); - $write = $except = null; - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - - if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) { - if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) { - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0)); - $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - $this->curTimeout-= $elapsed; - continue; - } - $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - $this->curTimeout-= $elapsed; - } - - $sec = floor($this->curTimeout); - $usec = 1000000 * ($this->curTimeout - $sec); - - // on windows this returns a "Warning: Invalid CRT parameters detected" error - if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { - $this->is_timeout = true; - if ($client_channel == NET_SSH2_CHANNEL_EXEC && !$this->request_pty) { - $this->_close_channel($client_channel); - } - return true; - } - $elapsed = strtok(microtime(), ' ') + strtok('') - $start; - $this->curTimeout-= $elapsed; - } - $response = $this->_get_binary_packet(true); if ($response === false) { $this->bitmap = 0;