-
Notifications
You must be signed in to change notification settings - Fork 7.7k
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
SSL handshake timeout leaves persistent connections hanging #8409
Comments
This looks related to https://bugs.php.net/bug.php?id=79501. |
Just FYI I have got this on my list with relatively high priority. Although there's bunch of other things so it might take few months to get this resolved. |
Thanks for the update, let me know if there's something I can do to make duplication easier. |
I assume it's this, right? phpredis/phpredis#1726 . After reading it, it seems that it's specific to TLS 1.3. Can you confirm that it's just related to TLS 1.3? Also does this happen with the latest Redis server version? |
I ran this to check if tls version matters: <?php
set_error_handler(function($errno, $errstring, $errfile, $errline, $errcontext) {
var_dump(get_resources());
exit(1);
});
$socket = stream_socket_client("tlsv1.2://redis:6379", $error_code, $error_message, 0.2, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, stream_context_create(['tls' => ['verify_peer_name' => false]]));
echo "here"; Sorry, this is long. tl;dr: I am proposing that the internals stream code should close connections where the tls handshake has timed out before emitting a warning. For some context, I don't think the issue I'm seeing is the same as phpredis/phpredis#1726 This was because the stream internals code emits a warning when the tls handshake times out, and then returns the connection to the phpredis extension, and the phpredis extension attempts to work with the connection, notices communication problems, and closes the connection, except if an error handler exists that stops execution in the case of warnings. In that case, the connection is not closed. |
I took a closer look on this one and the problem is basically that there is an area of code in php-src/main/streams/transports.c Lines 130 to 182 in 80197c5
I think it's not very practical handle it in every function that triggers error but instead store the errors and emit them later (after freeing the stream). The good thing that we have got already in core (used for inheritance) some functionality to record errors so I will take a look if we could modify that slightly so we can do just record and then reply it after the stream is cleaned up. |
This is not actually related to SSL handshake but stream socket creation which does not clean errors if the error handler is set. This fix prevents emitting errors until the stream is freed.
This is not actually related to SSL handshake but stream socket creation which does not clean errors if the error handler is set. This fix prevents emitting errors until the stream is freed.
Just for the record, the fix should be part of 8.1.10 . It's unfortunately non trivial task to back port the changes to 8.0 in an ABI compatible way as it relies on additions in 8.1 so it won't be part of 8.0. |
Thank you for the fix here! |
Hi @bukka |
This patch reverts part of d052742, d052742 makes Swoole/Swow can not work anymore, because Coroutine will yield to another one during socket operation, and EG(record_errors) assertion will always fail, and zend_begin_record_errors was only used during compile time before. Use zend_try and zend_catch to fix it, and this patch also can be applied to PHP-8.0.
Ah yeah forgot about generators. You right I should have used |
* PHP-8.0: Re-fix GH-8409: SSL handshake timeout persistent connections hanging
Description
We have a redis server, we're using the phpredis extension to connect to it. The phpredis extension is built on top of php's stream sockets. The bug I'm reporting can be duplicated without the phpredis extension.
Sometimes, a redis server will timeout during the ssl negotiation. This will generate a warning from
php_openssl_enable_crypto()
. If there is an error handler that stops execution on warnings, then the underlying connection will be left in place, even without SSL negotiation succeeding. We can see this by looking atclient list
on the redis server. The connection will still be hanging around, for as long as the fpm process exists.For testing purposes, we can disable tls on the redis server, which will force the "handshake timed out" results.
Is there a reason that the connection is maintained even if the ssl negotiation fails? Could/should php close the connection when ssl negotiation fails?
The following code:
Resulted in this output:
But I expected this output instead:
PHP Version
PHP 7.4.28
Operating System
Ubuntu 20.04
The text was updated successfully, but these errors were encountered: