Project

General

Profile

Bug #12678

No way to set a timeout for TLS handshake when using Net::SMTP

Added by benweint (Ben Weintraub) over 3 years ago. Updated over 2 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
[ruby-core:76893]

Description

When establishing a connection to an SMTP server, Net::SMTP doesn't offer a way to specify a timeout for how long the TLS handshake should take.

In our production environment, this means we routinely see hangs under this callstack:

.../lib/ruby/2.1.0/net/smtp.rb:586:in connect'
.../lib/ruby/2.1.0/net/smtp.rb:586:in
tlsconnect'
.../lib/ruby/2.1.0/net/smtp.rb:563:in do_start'
.../lib/ruby/2.1.0/net/smtp.rb:520:in
start'
.../shared/bundle/ruby/2.1.0/gems/mail-2.5.4/lib/mail/network/delivery_methods/smtp.rb:112:in `deliver!'

The C-level backtrace here looks like this:

Thread 1 (Thread 0x7f7709587700 (LWP 30870)):
#0 0x00007f77085ea4b7 in ppoll () from /lib64/libc.so.6
#1 0x00007f7709719cd9 in rb_wait_for_single_fd (fd=, events=, tv=0x0) at thread.c:3675
#2 0x00007f7709719e32 in rb_thread_wait_fd_rw (fd=) at thread.c:3514
#3 rb_thread_wait_fd (fd=) at thread.c:3525
#4 0x00007f77095f08bf in rb_io_wait_readable (f=34) at io.c:1094
#5 0x00007f77009aa894 in ossl_start_ssl (self=140149417009120, func=0x7f7700755570 , funcname=0x7f77009c3ba7 "SSL_connect", nonblock=) at ossl_ssl.c:1282
#6 0x00007f77096f522a in vm_call_cfunc_with_frame (th=0x7f770a9585b0, reg_cfp=0x7f7709583530, ci=) at vm_insnhelper.c:1510
#7 0x00007f7709708e11 in vm_call_cfunc (th=0x7f770a9585b0, cfp=0x7f7709583530,

You can replicate this behavior by starting a dummy server using 'nc' (netcat), and then running the attached ruby script to connect to it.

Steps to reproduce:

  1. Start a netcat process listening on port 8888 ('nc -l 8888')
  2. Run the attached net-smtp-connect-timeout.rb
  3. Wait

Expected results:

The call to smtp.start should eventually time out.

Actual results:

The call to smtp.start hangs forever.

Notes:

Net::HTTP addresses this same issue by using a loop around SSLSocket.connect_nonblock:
https://github.com/ruby/ruby/blob/trunk/lib/net/http.rb#L934-L943

... seems like Net::SMTP should do the same.

We're hitting this issue using Ruby 2.1.7 in production, but I've also verified that it happens on 2.3.1.


Related issues

Has duplicate Ruby master - Bug #13429: Net::SMTP has no read timeout when connexion over TLSClosedActions

Associated revisions

Revision 73b3b10d
Added by shugo (Shugo Maeda) about 3 years ago

  • lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
    [ruby-core:76893] [Bug #12678]

  • lib/net/protocol.rb (ssl_socket_connect): new method to implement
    timeout for TLS handshake.

  • lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 56576
Added by shugo (Shugo Maeda) about 3 years ago

  • lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
    [ruby-core:76893] [Bug #12678]

  • lib/net/protocol.rb (ssl_socket_connect): new method to implement
    timeout for TLS handshake.

  • lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

Revision 56576
Added by shugo (Shugo Maeda) about 3 years ago

  • lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
    [ruby-core:76893] [Bug #12678]

  • lib/net/protocol.rb (ssl_socket_connect): new method to implement
    timeout for TLS handshake.

  • lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

Revision 56576
Added by shugo (Shugo Maeda) about 3 years ago

  • lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
    [ruby-core:76893] [Bug #12678]

  • lib/net/protocol.rb (ssl_socket_connect): new method to implement
    timeout for TLS handshake.

  • lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

Revision 56576
Added by shugo (Shugo Maeda) about 3 years ago

  • lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
    [ruby-core:76893] [Bug #12678]

  • lib/net/protocol.rb (ssl_socket_connect): new method to implement
    timeout for TLS handshake.

  • lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

Revision 56623
Added by shugo (Shugo Maeda) about 3 years ago

  • test/net/smtp/test_smtp.rb (test_tls_connect, test_tls_connect): use Socket.tcp_server_sockets in case localhost is resolved to ::1.

Revision 87cacf7e
Added by usa (Usaku NAKAMURA) over 2 years ago

merge revision(s) 56576,56623: [Backport #12678] [Backport #13429]

    * lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
      [ruby-core:76893] [Bug #12678]

    * lib/net/protocol.rb (ssl_socket_connect): new method to implement
      timeout for TLS handshake.

    * lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

    * test/net/smtp/test_smtp.rb (test_tls_connect, test_tls_connect):
      use Socket.tcp_server_sockets in case localhost is resolved to ::1.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_3@59533 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 59533
Added by usa (Usaku NAKAMURA) over 2 years ago

merge revision(s) 56576,56623: [Backport #12678] [Backport #13429]

* lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
  [ruby-core:76893] [Bug #12678]

* lib/net/protocol.rb (ssl_socket_connect): new method to implement
  timeout for TLS handshake.

* lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

* test/net/smtp/test_smtp.rb (test_tls_connect, test_tls_connect):
  use Socket.tcp_server_sockets in case localhost is resolved to ::1.

History

Updated by shyouhei (Shyouhei Urabe) about 3 years ago

  • Assignee set to shugo (Shugo Maeda)
  • Status changed from Open to Assigned
#2

Updated by shugo (Shugo Maeda) about 3 years ago

  • Status changed from Assigned to Closed

Applied in changeset r56576.


  • lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
    [ruby-core:76893] [Bug #12678]

  • lib/net/protocol.rb (ssl_socket_connect): new method to implement
    timeout for TLS handshake.

  • lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.

#3

Updated by shugo (Shugo Maeda) over 2 years ago

  • Has duplicate Bug #13429: Net::SMTP has no read timeout when connexion over TLS added

Updated by usa (Usaku NAKAMURA) over 2 years ago

  • Backport changed from 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN to 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: DONE

ruby_2_3 r59533 merged revision(s) 56576,56623.

Also available in: Atom PDF