Dmytro Shteflyuk created THRIFT-6120:
----------------------------------------

             Summary: Ruby SSLServerSocket client timeout does not cover the 
TLS handshake
                 Key: THRIFT-6120
                 URL: https://issues.apache.org/jira/browse/THRIFT-6120
             Project: Thrift
          Issue Type: Bug
          Components: Ruby - Library
            Reporter: Dmytro Shteflyuk
            Assignee: Dmytro Shteflyuk


h3. Problem

{{Thrift::SSLServerSocket}} applies {{client_timeout}} only after 
{{OpenSSL::SSL::SSLServer#accept}} has completed. That accept call performs the 
TLS handshake before the accepted connection is wrapped in a 
{{Thrift::Socket}}, so the configured timeout cannot interrupt a client that 
opens TCP but does not finish TLS negotiation.

h3. Client impact

A client that connects and then sends no TLS handshake data, or sends only a 
partial handshake, can leave the server blocked in {{accept}} beyond the 
configured client timeout. In {{SimpleServer}}, accepting connections happens 
on the server thread, so no later client can be accepted until that handshake 
completes or the peer disconnects.

Successful TLS connections are unaffected; the problem is that the timeout 
begins too late to cover the TLS setup it is expected to bound.

h3. Reproduction

>From {{lib/rb}}, run the following against the current implementation:

{code:ruby}
require "openssl"
require "socket"
require "thrift"

context = OpenSSL::SSL::SSLContext.new
context.cert = OpenSSL::X509::Certificate.new(
  File.read("../../test/keys/server.crt")
)
context.key = OpenSSL::PKey::RSA.new(
  File.read("../../test/keys/server.key")
)

server = Thrift::SSLServerSocket.new(
  "127.0.0.1",
  0,
  context,
  client_timeout: 0.05
)
server.listen

client = TCPSocket.new(
  "127.0.0.1",
  server.to_io.local_address.ip_port
)
accept_thread = Thread.new { server.accept }

sleep 0.2
puts(
  "configured_client_timeout=0.05 " \
  "accept_still_blocked_after=0.2 " \
  "timed_out=#{accept_thread.alive?}"
)

client.close
accept_thread.join
server.close
{code}

The configured timeout is 50 milliseconds, but after 200 milliseconds the 
accept operation is still blocked:

{code}
configured_client_timeout=0.05 accept_still_blocked_after=0.2 timed_out=true
{code}

The same behavior occurs when the peer sends an incomplete TLS handshake and 
then stops.

h3. Expected behavior

The configured client timeout should apply to TLS negotiation as one monotonic 
deadline. If the handshake does not complete in time, the accepted socket 
should be closed and {{accept}} should raise a typed TLS error so the server 
can continue accepting other connections. A completed TLS handshake should 
still return a normal {{Thrift::Socket}} with the configured timeout.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to