Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection closed prematurely #1529

Closed
matiniamirhossein opened this issue Sep 11, 2020 · 37 comments
Closed

Connection closed prematurely #1529

matiniamirhossein opened this issue Sep 11, 2020 · 37 comments

Comments

@matiniamirhossein
Copy link

Using:
PHP 7.3.21
phpseclib 2.0.29

I'm trying to run a very long running command (like 1 hour or more) with this function, as this function runs more than ClientAliveInterval * ClientAliveCountMax ~ 10 mins (default) I get error Connection closed prematurely.

I switched to this library from php ssh2 extension, back there I had no problem with this.

https://www.php.net/manual/en/function.ssh2-exec.php

Is there any command or setting to send server that we are still alive as client?

Thanks in advance.

function runSSHCommandWithCallback($ip, $port, $username, $password, $cmd, callable $callback, $timeout = 10800){
    $connection = new SSH2($ip, $port);
    if (!$connection->login($username, $password)) {
        throw new SSHException("SSH Authentication failed");
    }
    $connection->enableQuietMode();
    $connection->setTimeout($timeout);
    $output = $connection->exec($cmd, function($output) use ($callback) {
        $error = $connection->getStdError();
        if(!empty($error)){
            throw new SSHErrorException($error);
        }
        if (is_callable($callback)) {
            $callback($output);
        }
    });
    $error = $connection->getStdError();
    if(!empty($error)){
        throw new SSHErrorException($error);
    }
}
@terrafrost
Copy link
Member

You could do something like this:

<?php
include('Net/SSH2.php');

$ssh = new Net_SSH2('www.website.com');
$ssh->login('username', 'password');

$ssh->write("ping 127.0.0.1\n");

echo $ssh->exec('sleep 3600s; ls -latr');

@matiniamirhossein
Copy link
Author

@terrafrost Thanks, but really is there is or gonna be a fix for this? I currently solved my problem by increasing ClientAliveInterval. All good now.

@terrafrost
Copy link
Member

Thanks, but really is there is or gonna be a fix for this?

idk why libssh2 doesn't time out whereas phpseclib does. What'd be more useful is if PuTTY doesn't time out as I can get the SSH packet logs from that.

That said, in lieu of having looked into it, it's quite possible that other SSH clients that don't time out are employing multiple threads. ie. one thread waits for responses whereas another thread sends periodic SSH2_MSG_IGNORE packets or something. In that scenario, duplicating that behavior would be quite difficult as PHP isn't multi threaded.

Anyway, I'll try to look into it at some point.

@makanbaks0-zz
Copy link

Hi, I got this when using it on https://github.com/respawner/looking-glass

PHP Notice: Connection closed prematurely in /looking-glass/libs/phpseclib-2.0.29/Net/SSH2.php on line 3936

and there is no ssh log, any solution?

@terrafrost
Copy link
Member

I added a setKeepAlive method in this branch:

https://github.com/terrafrost/phpseclib/tree/keepalive-2.0

LMK if it solves the problem for y'all.

Thanks!

@makanbaks0-zz
Copy link

Hi..
I tried it, but I got
Connection closed prematurely in /looking-glass/libs/phpseclib-2.0.23/Net/SSH2.php on line 3972

I downloaded https://github.com/terrafrost/phpseclib/archive/keepalive-2.0.zip
and replace all phpseclib-2.0.23 with yours.

@terrafrost
Copy link
Member

Did it send NET_SSH2_MSG_IGNORE packets every x seconds as you'd expect? You can verify this by doing define('NET_SSH2_LOGGING', 3); at the top and seeing the packets it's sending real time.

The NET_SSH2_MSG_IGNORE approach is what PuTTY does when you enter in a non-zero value for "Seconds between keepalives (0 to turn off)" in the Connections "tab".

OpenSSH seems to employ another approach - it sends a keepalive@openssh.com SSH2_MSG_CHANNEL_REQUEST which will most likely result in the other end sending a SSH2_MSG_CHANNEL_FAILURE response.

I tried to reproduce the issue locally by running a long running command. I disabled ServerAliveInterval and ServerAliveCountMax (or rather, I set them to 0) and then tried to run a long running command and I didn't get any timeouts with either PuTTY or the OpenSSH client:

https://superuser.com/q/1588942/172193

In the case of PuTTY the server kept on sending the keepalive@openssh.com SSH2_MSG_CHANNEL_REQUEST even after ServerAliveCountMax had been passed. That's probably what's happening with the OpenSSH client as well. Like in neither cases is the client actually doing anything to keep the connection alive - it's the server that's doing all the work. But in your case the server I guess isn't doing any work after ServerAliveCountMax has been hit? If so then that is not something that I've been able to reproduce...

@Echron
Copy link

Echron commented Nov 27, 2020

@terrafrost I'm getting a similar issue with version 3 of the library when trying to execute a long running script (with constant output so it's not an idle connection).
Connection closed prematurely at SSH2.php:3199
Apparently, it's feof()who is suddenly true while there is definitely more output coming.
The odd thing is that it's always around 2 minutes.
It might be settings in the server, unfortunate I can't access the servers configuration to do any modifications but I see that ClientAliveInterval is set to 30 and TCPKeepAlive is set to yes. There is no setting for ClientAliveCountMax but according to the documentation the default value is 3. So if we have the initial connection of 30 seconds + 3 x ClientAliveCountMax = 120 seconds. This seems the only way I can get to 120 seconds.

I tried implementing the keepalive-2.0 changes but I don't directly see any keep alive packages being send. If I read the code correctly the keepalive "NET_SSH2_MSG_IGNORE" is only send when stream_select returns false.

I believe your last paragraph is correct since I checked the putty settings and see that the keep alive there is 0 (no keep alive is send) for the session that I use to connect to this server and timeouts are happening. So something must be missing to keep the connection alive.

I'm willing to do some research but my knowledge of the SSH protocol and working with streams is pretty limited.

@Echron
Copy link

Echron commented Nov 27, 2020

@terrafrost I was just able to execute a 50 minutes script by sending the NET_SSH2_MSG_IGNORE package at the keepalive intervals. As soon as I have some time I will implement it on a fork so you can have a look and share me your opinion on it.

I've made a fork with my changes here:
https://github.com/Echron/phpseclib/tree/keepalive

@terrafrost
Copy link
Member

@Echron - I'll check it out - thanks!!

@Xachman
Copy link

Xachman commented Dec 10, 2020

This also seems to have been working in version 2.0.13. I am currently updating a project using laravelcollective/remote and updating has this issue but the old version of the application does not.

@terrafrost
Copy link
Member

I totally forgot about @Echron 's changes lol. I'm not gonna be able to check them out today but hopefully this weekend!

Thanks for the unintentional reminder @Xachman lol

@Echron
Copy link

Echron commented Dec 11, 2020

@terrafrost
I'm getting good results at the moment BUT I had to catch an empty response on line 3704 (in my altered code)
if($response === '') { echo 'Temp fix when response is empty'.\PHP_EOL; return true; } list($type, $channel) = Strings::unpackSSH2('CN', $response);
Because unpack SSH2 doesn't like to receive an empty string.
Not sure if this is because of the keepalive or another bug. I didn't push that code to my branch so you can check it out yourself.

Off the record: are you using any automated (end to end) tests? Besides this ticket that is covering a rare bug/functionality, I've been going through your code and there are so many cases and statements. I see in you are planning on refactoring a lot, there should be some ways to test most of this.

@terrafrost
Copy link
Member

@Echron - there are unit tests but a lot of the edge cases I've encountered over the years there's no easy way to test.

Consider the window size handling stuff. I have absolutely no idea how to control the window size that OpenSSH uses. I suppose I could modify the OpenSSH source code and then have 15 different compiled versions but I am not going to do that.

A lot of issues I've never actually been able to test first hand either. Someone posts log files and I develop a hypothesis from those log files and then I make a change in my fork of phpseclib and I ask the person if that change fixes the issue for them. If it does I merge it in, in many cases, never having been able to reproduce it directly myself.

I suppose I could write a pure-PHP SSH server to test some of these conditions, but again, I am absolutely not going to do that. That would be a gargantuan task that I'm not even sure would be that beneficial as all I'd be doing is emulating my understanding of what problem server is doing (which might not be what problem servers are actually doing)

@terrafrost
Copy link
Member

@Echron - like even this one. I can't even reproduce this issue. https://superuser.com/q/1588942/172193 documents my attempt to do so which was a bit of a dead end. If I can't reproduce on my personal laptop then it stands to reason that reproducing it on Travis CI or any other CI platform is going to be beyond my ability!

@Xachman
Copy link

Xachman commented Dec 11, 2020

@terrafrost This does not happen when I run ssh directly with popen. I had to switch to this in the meantime since I have some ssh commands that run and do not return any data back for a long time.

@terrafrost
Copy link
Member

@Xachman - that doesn't help me reproduce the issue.

Anyway, as I said, I'll look at this hopefully within the next few days. My most immediate priority is getting phpseclib unit tested on PHP 8, which has now been out for like a week.

@Xachman
Copy link

Xachman commented Dec 12, 2020

@terrafrost Sorry I thought the issue itself was pretty easy to reproduce with the sleep command you posted without the ping. Are you saying you have never experienced this issue? I'm sure I could throw together a environment where this happens using docker if that's the case.

@terrafrost
Copy link
Member

@terrafrost Sorry I thought the issue itself was pretty easy to reproduce with the sleep command you posted without the ping. Are you saying you have never experienced this issue? I'm sure I could throw together a environment where this happens using docker if that's the case.

I'm able to semi reproduce the issue with this Vagrantfile (it's easier to setup SSH with Vagrant than it is with Docker):

Vagrant.configure("2") do |config|
    config.vm.box = "laravel/homestead"
    config.vm.provision "shell", inline: <<-SHELL
        printf "\n\nClientAliveInterval 3\nClientAliveCountMax 2" >> /etc/ssh/sshd_config
        service ssh restart
    SHELL
end

BUT https://github.com/terrafrost/phpseclib/tree/keepalive-2.0 works with that Vagrantfile:

$ssh = new SSH2('vagrant');
$ssh->login('vagrant', 'vagrant');
$ssh->setTimeout(0);
$ssh->setKeepAlive(2);

echo $ssh->exec('sleep 15s');

echo $ssh->exec('ls -latr');

If I comment out $ssh->setKeepAlive(2) I get the "connection closed prematurely" error whereas I don't if I leave it in place.

And yet, despite working for me, it doesn't work for @Echron . So that's what I'm not able to reproduce. idk how to set OpenSSH up such that my proposed fix doesn't work...

@terrafrost
Copy link
Member

I backported Echron's keep-alive code to the 1.0 branch here:

https://github.com/terrafrost/phpseclib/tree/alt-keep-alive-1.0

In comparing that to my own implementation (https://github.com/terrafrost/phpseclib/tree/keepalive-1.0)...

Consider the scenario where the timeout is 0 (ie. nothing should timeout) and keep alive is non-zero. Echron's implementation checks to see if more than x seconds have passed since the last keep-alive packet was sent and, if so, sends the keep-alive packet. My implementation, otoh, sends the keep-alive packet after waiting for up to x seconds for the next packet to become available (via the select system call). x, in this case, is the keep-alive amount. It looks like his implementation is largely adapted from my own.

Using the test code and Vagrantfile I posted in my last post, here's the relevant parts of the SSH logs from Echron's implementation:

-> NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0002, network: 0.0001s)
00000000  00:00:00:00:00:00:00:04:65:78:65:63:01:00:00:00  ........exec....
00000010  09:73:6c:65:65:70:20:31:35:73                    .sleep 15s

<- NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST (since last: 0.0009, network: 0.0009s)
00000000  00:00:00:01:00:20:00:00                          ..... ..

<- NET_SSH2_MSG_CHANNEL_SUCCESS (since last: 0.0001, network: 0s)
00000000  00:00:00:01                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 3.0008, network: 3.0007s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

-> NET_SSH2_MSG_IGNORE (since last: 0.0008, network: 0.0001s)
00000000  00:00:00:00                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 3.0043, network: 3.0042s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

-> NET_SSH2_MSG_IGNORE (since last: 0.001, network: 0.0002s)
00000000  00:00:00:00                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 3.0042, network: 3.0041s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

-> NET_SSH2_MSG_IGNORE (since last: 0.0006, network: 0.0001s)
00000000  00:00:00:00                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 3.0042, network: 3.0041s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

-> NET_SSH2_MSG_IGNORE (since last: 0.0008, network: 0.0002s)
00000000  00:00:00:00                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 2.9848, network: 2.9847s)
00000000  00:00:00:01:00:00:00:15:6b:65:65:70:61:6c:69:76  ........keepaliv
00000010  65:40:6f:70:65:6e:73:73:68:2e:63:6f:6d:01        e@openssh.com.

-> NET_SSH2_MSG_IGNORE (since last: 0.0005, network: 0.0001s)
00000000  00:00:00:00                                      ....

<- NET_SSH2_MSG_CHANNEL_EOF (since last: 0.0001, network: 0s)
00000000  00:00:00:01                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0s)
00000000  00:00:00:01:00:00:00:0b:65:78:69:74:2d:73:74:61  ........exit-sta
00000010  74:75:73:00:00:00:00:00                          tus.....

<- NET_SSH2_MSG_CHANNEL_CLOSE (since last: 0, network: 0s)
00000000  00:00:00:01                                      ....

-> NET_SSH2_MSG_CHANNEL_CLOSE (since last: 0.0001, network: 0s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_CHANNEL_OPEN (since last: 0.0001, network: 0s)
00000000  00:00:00:07:73:65:73:73:69:6f:6e:00:00:00:01:7f  ....session.....
00000010  ff:ff:ff:00:00:40:00                             .....@.

<- NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION (since last: 0.0006, network: 0.0006s)
00000000  00:00:00:01:00:00:00:00:00:00:00:00:00:00:80:00  ................

-> NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0.0001s)
00000000  00:00:00:00:00:00:00:04:65:78:65:63:01:00:00:00  ........exec....
00000010  08:6c:73:20:2d:6c:61:74:72                       .ls -latr

Here's the relevant portion from my implementation:

-> NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0001, network: 0.0001s)
00000000  00:00:00:00:00:00:00:04:65:78:65:63:01:00:00:00  ........exec....
00000010  09:73:6c:65:65:70:20:31:35:73                    .sleep 15s

<- NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST (since last: 0.0011, network: 0s)
00000000  00:00:00:01:00:20:00:00                          ..... ..

<- NET_SSH2_MSG_CHANNEL_SUCCESS (since last: 0, network: 0s)
00000000  00:00:00:01                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2.0004, network: 0.0002s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2.0002, network: 0.0002s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2, network: 0.0002s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2.0003, network: 0.0002s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2.0006, network: 0.0002s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2.0005, network: 0.0002s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_IGNORE (since last: 2.001, network: 0.0002s)
00000000  00:00:00:00                                      ....

<- NET_SSH2_MSG_CHANNEL_EOF (since last: 0.9987, network: 0.0001s)
00000000  00:00:00:01                                      ....

<- NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0002, network: 0.0001s)
00000000  00:00:00:01:00:00:00:0b:65:78:69:74:2d:73:74:61  ........exit-sta
00000010  74:75:73:00:00:00:00:00                          tus.....

<- NET_SSH2_MSG_CHANNEL_CLOSE (since last: 0.0001, network: 0s)
00000000  00:00:00:01                                      ....

-> NET_SSH2_MSG_CHANNEL_CLOSE (since last: 0.0002, network: 0.0001s)
00000000  00:00:00:00                                      ....

-> NET_SSH2_MSG_CHANNEL_OPEN (since last: 0.0001, network: 0s)
00000000  00:00:00:07:73:65:73:73:69:6f:6e:00:00:00:01:7f  ....session.....
00000010  ff:ff:ff:00:00:40:00                             .....@.

<- NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION (since last: 0.0009, network: 0.0001s)
00000000  00:00:00:01:00:00:00:00:00:00:00:00:00:00:80:00  ................

-> NET_SSH2_MSG_CHANNEL_REQUEST (since last: 0.0002, network: 0.0001s)
00000000  00:00:00:00:00:00:00:04:65:78:65:63:01:00:00:00  ........exec....
00000010  08:6c:73:20:2d:6c:61:74:72                       .ls -latr

So one thing to note is that my implementation sends a NET_SSH2_MSG_IGNORE message every 2s (which is consistent with the setKeepAlive parameter). Echron's implementation sends it out every 3s (ClientAliveInterval in the Vagrantfile). ie. it waits until it's gotten a NET_SSH2_MSG_CHANNEL_REQUEST packet to send it's NET_SSH2_MSG_IGNORE. This is because his code can't actually "pause" it's _get_binary_packet request to send it's NET_SSH2_MSG_IGNORE packet whereas mine can (via the select system call).

So what about when the phpseclib keep-alive interval is greater than the server's ClientAliveInterval? eg. instead of $ssh->setKeepAlive(2) we'll do $ssh->setKeepAlive(5).

In this case both implementations get a "Connection closed prematurely" error.

I'll mull it over some more but I'm currently leaning towards going with my implementation, altho I'd still like to get it working for the use case where both are currently failing.

@terrafrost
Copy link
Member

Another scenario to consider: what if ClientAliveCountMax is 0? My implementation works (with $ssh->setKeepAlive(2) and ClientAliveInterval being 3) whereas Echron's doesn't.

For the scenario when the keep-alive interval is greater than the server's ClientAliveInterval... I think making it so phpseclib return a NET_SSH2_MSG_IGNORE packet when the server sends a keep-alive@openssh.com NET_SSH2_MSG_CHANNEL_REQUEST would be good. That's not going to work if ClientAliveCountMax is also 0 but there's only so much that I figure can realistically be done!

@terrafrost
Copy link
Member

I have four new branches with these improvements:

https://github.com/terrafrost/phpseclib/tree/keepalive-1.0
https://github.com/terrafrost/phpseclib/tree/keepalive-2.0
https://github.com/terrafrost/phpseclib/tree/keepalive-3.0
https://github.com/terrafrost/phpseclib/tree/keepalive-master

The unit tests are running right now. If they pass I'll merge this into phpseclib/phpseclib this evening and will release a new version of 2.0 and do the maiden release of 3.0.

In the mean time, feel free to test these changes out!

@Xachman
Copy link

Xachman commented Dec 15, 2020

https://github.com/Xachman/test-ssh Using this test environment with the standard php:7 environment and ubuntu trusty as the environment you ssh into the current phpseclib 2.0 connection drops with $ssh->exec('sleep 300; ls -al'); before outputting the ls. Then trying with the keepalive-2.0 branch it just seemed to drop faster. running ssh root@ubuntu "sleep 300; ls -al" works fine.

@terrafrost
Copy link
Member

I'm not seeing $ssh->setKeepAlive(whatever) in your php-ssh.php/test_ssh.php. It's not enabled by default. I mean, I guess I could keep it enabled by default but idk.

it just seemed to drop faster

You could empirically test that by doing $start = microtime(true); before the command and $elapsed = microtime(true) - $start; echo "took $elapsed seconds"; with both branches

@Xachman
Copy link

Xachman commented Dec 15, 2020

I tried with $ssh->setKeepAlive(5); and the results are the same. I really want to spend some more time with this now that I have a small test environment that seems to be doing the same thing. I can hop on it after work today or tomorrow.

@terrafrost
Copy link
Member

I use Docker a fair amount (see https://github.com/phpseclib/docker-php) but have never used docker-compose. I did the following:

git clone https://github.com/Xachman/test-ssh
cd test-ssh
docker-compose up

Here's what I got in response:

ERROR: The Compose file './docker-compose.yml' is invalid because:
Unsupported config option for services: 'ubuntu'

I've Google'd that without a ton of success. None of the following links seem very helpful:

https://forums.docker.com/t/docker-compose-yml-is-invalid-because-unsupported-config/51463
https://stackoverflow.com/a/58390024/569976
etc

From the links I gather indentation matters but I feel like if all I did was git clone that it ought to work out of the box with zero code changes and it doesn't...

In lieu of that... can you do define('NET_SSH2_LOGGING', 2); at the top and then echo $ssh->getLog();? Once you get the output can you post it on pastebin.com and share the link?

Thanks!

@terrafrost
Copy link
Member

Well, actually, docker-composer up seems to be giving me one of two different errors randomly. The other error I'm randomly getting is this one:

ERROR: The Compose file './docker-compose.yml' is invalid because:
Unsupported config option for services: 'php-ssh'

@terrafrost
Copy link
Member

I tried with $ssh->setKeepAlive(5); and the results are the same.

Looking at your code I see one other thing you should do... you'll need to adjust the timeout as well. You can disable the timeout by doing $ssh->setTimeout(0);. By default phpseclib times out after 10s of inactivity. This can be changed, like I said, with the $ssh->setTimeout(0) call.

If you're still having issues update https://github.com/Xachman/test-ssh/blob/main/php-ssh/test_ssh.php accordingly and commit your changes. Since you're going this Docker route I feel like I shouldn't have to copy / past anything other than the URL to reproduce the issue - git clone ... && cd ... & docker-compose up should be all I need to do to reproduce the issue.

@Xachman
Copy link

Xachman commented Dec 16, 2020

@terrafrost I added the setTimeout and that did work was able to sleep for 300 seconds and output the ls.

changes are https://github.com/Xachman/test-ssh/blob/main/php-ssh/test_ssh.php

Adding the code if anyone needed the example. And I deleted that.

<?php

use phpseclib\Crypt\RSA;
use phpseclib\Net\SSH2;

require_once './vendor/autoload.php';

$ssh = new SSH2('ubuntu');
$rsa = new RSA();
$rsa->loadKey(file_get_contents('/root/.ssh/id_rsa'));
var_dump($ssh->login('root', $rsa));

$ssh->setTimeout(0);
$ssh->setKeepAlive(5);


echo $ssh->exec('sleep 300; ls -al');

I added a docker-compose version string to the docker-compose.yml in case that was the issue. Could be that you are using an older version of docker-compose but I'm not 100%. If you want to try it out you just make an id_rsa in a folder called build in php-ssh and put the id_rsa.pub in a folder called build in ubuntu. php-ssh could be able to ssh into ubuntu using the docker network service name ubuntu as the host.

@Xachman
Copy link

Xachman commented Dec 17, 2020

My last comment was a mistake if you got the email on it. Ran the wrong test.

@Xachman
Copy link

Xachman commented Dec 17, 2020

I was able to confirm the keep alive changes do keep the connection alive to the original AWS EC2 instance I had this issue with. I had to run the test again because my original test used the connection to the local ubuntu container.

My environment does not replicate the issue. I was confused because of the set timeout part. These changes do fix the issue for my use case though. Since I came from laravelcollective/remote I will make an issue there once these changes get merged and I would assume they aren't going to be immediately implemented there.

@terrafrost
Copy link
Member

Thanks for the feedback!!

@terrafrost
Copy link
Member

The branches have been merged. I'll do a new release shortly!

@Echron
Copy link

Echron commented Dec 21, 2020

I installed 3.0.0 tested it on the servers that gave issues before and everything seems to work really well. Good work!

@insiderinside
Copy link

Encountered exception: Connection closed prematurely in line: 3195

@insiderinside
Copy link

2021-11-02 19:55:39 - getting data from xxrouterhost
2021-11-03 00:47:21 - xxrouterhost Encountered exception: Connection closed prematurely in line: 3195
Take time 5 hours.

@terrafrost
Copy link
Member

@insiderinside - can you post the SSH logs? You can get them by doing define('NET_SSH2_LOGGING', 2); at the top and then echo $ssh->getLog(); after you get the error.

If you could also post your code too, obviously redacting any passwords / public keys or any other sensitive info you might have, that'd be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants