Project

General

Profile

Actions

Bug #21104

open

Net::HTTP connections failing in Ruby >= 3.4.0 on macOS with Happy Eyeballs enabled

Added by mjt58 (Mike Thompson) 20 days ago. Updated 2 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
[ruby-core:120855]

Description

A project I work on recently upgraded Ruby to 3.4.1 from 3.3.5. Following the upgrade, and when running locally on my Mac, all attempts to connect to an external service within the project over http(s) fail.

We use mise for managing development tool dependencies, including Ruby, and I am using macOS 15.3.

For example running something as simple as:

require 'net/http'
puts Net::HTTP.get(URI('https://bbc.co.uk'))

Will fail with the following stack trace:

/path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/protocol.rb:46:in 'OpenSSL::SSL::SSLSocket#connect_nonblock': Connection reset by peer - SSL_connect (Errno::ECONNRESET)
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/protocol.rb:46:in 'Net::Protocol#ssl_socket_connect'
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/http.rb:1736:in 'Net::HTTP#connect'
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/http.rb:1636:in 'Net::HTTP#do_start'
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/http.rb:1625:in 'Net::HTTP#start'
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/http.rb:1064:in 'Net::HTTP.start'
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/http.rb:824:in 'Net::HTTP.get_response'
	from /path/to/.local/share/mise/installs/ruby/3.4.1/lib/ruby/3.4.0/net/http.rb:805:in 'Net::HTTP.get'
	from request.rb:2:in '<main>'

I tried different versions of Ruby and confirmed that the issue appears with 3.4.0. After reading the release notes for this version, I tried setting RUBY_TCP_NO_FAST_FALLBACK=1 and this worked, allowing me to work around the problem.

This issue has also been encountered by others, please see:
https://github.com/rubygems/rubygems/issues/8390

Updated by shioimm (Misaki Shioi) 20 days ago

I suspect that this issue might be caused by an interaction between the specifications of Happy Eyeballs v2 and certain intermediate devices along the network path.
This is because, according to the report you linked, the problem occurs for some people but not for others, even though they are using the same OS, the same Ruby version, the same OpenSSL version, and connecting to the same destination (https://rubygems.org/). I also haven't been able to reproduce this issue in my own environment.

To help narrow down the cause, could you provide more information on the following?

  • You specified 'https://bbc.co.uk' as the host you're connecting to. Does the same issue occur when connecting to other hosts as well?
  • Does the issue still occur when you use a different network environment? For example, when connecting from your workplace, a cafe, or when using a VPN?

Updated by mjt58 (Mike Thompson) 19 days ago

shioimm (Misaki Shioi) wrote in #note-1:

To help narrow down the cause, could you provide more information on the following?

  • You specified 'https://bbc.co.uk' as the host you're connecting to. Does the same issue occur when connecting to other hosts as well?

Yes, I saw it first running bundle install with errors like:

Bundler::HTTPError Could not fetch specs from https://rubygems.org/ due to underlying error <Errno::ECONNRESET: Connection reset by peer - SSL_connect (https://rubygems.org/specs.4.8.gz)>
  • Does the issue still occur when you use a different network environment? For example, when connecting from your workplace, a cafe, or when using a VPN?

Yes, I see it on, home wifi, office wifi and when tethered off my phone.

Updated by shioimm (Misaki Shioi) 18 days ago

@mjt58
Thank you for your reply. Since you're seeing this issue across different environments, I'm starting to think it's more likely influenced by software running on the host rather than a problem with network intermediaries.
Could you also check the following?

  • Do you get any errors when running TCPSocket.new directly without using net/http? For example, try executing a script like this:
require "socket"
p TCPSocket.new("bbc.co.uk", 80, fast_fallback: true)
  • Could you verify via packet capture whether the source IP of the RST is the client host itself? You can see which IP address sends an RST by using tcpdump, for example, by running sudo tcpdump -i <interface name> host bbc.co.uk, and then executing Net::HTTP.get(URI("https://bbc.co.uk")).

I'd appreciate your help with further debugging.

Updated by radarek (Radosław Bułat) 2 days ago · Edited

I have the same issue with ruby 3.4.1 and 3.4.2. Because of it I can not install gems (ie. gem install solargraph fails). Only using mentioned workaround (RUBY_TCP_NO_FAST_FALLBACK=1 gem install solargraph) I am able to do this. I have mac os, arm64 (m1) architecture.

@shioimm (Misaki Shioi)

require "socket"
p TCPSocket.new("bbc.co.uk", 80, fast_fallback: true)

It works for me (it outputs TCPSocket instance data).

I also tried to get some tcpdump output. With RBENV_VERSION=3.4.1 ruby -rnet/http -e 'Net::HTTP.get(URI("https://bbc.co.uk"))' I didn't get any output in tcpdump session.

I only got output with ruby 3.3.4 RBENV_VERSION=3.3.4 ruby -rnet/http -e 'Net::HTTP.get(URI("https://bbc.co.uk"))':

$ sudo tcpdump -i en0 host bbc.co.uk
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on en0, link-type EN10MB (Ethernet), snapshot length 524288 bytes
15:25:07.847222 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [S], seq 1483240036, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 4232487628 ecr 0,sackOK,eol], length 0
15:25:07.889327 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [S.], seq 1267008426, ack 1483240037, win 65535, options [mss 1396,sackOK,TS val 3060773048 ecr 4232487628,nop,wscale 9], length 0
15:25:07.889447 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [.], ack 1, win 2054, options [nop,nop,TS val 4232487671 ecr 3060773048], length 0
15:25:07.920700 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [P.], seq 1:518, ack 1, win 2054, options [nop,nop,TS val 4232487701 ecr 3060773048], length 517
15:25:07.955066 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [.], ack 518, win 273, options [nop,nop,TS val 3060773113 ecr 4232487701], length 0
15:25:07.957494 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [.], seq 1:1381, ack 518, win 273, options [nop,nop,TS val 3060773115 ecr 4232487701], length 1380
15:25:07.957497 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [P.], seq 1381:2761, ack 518, win 273, options [nop,nop,TS val 3060773115 ecr 4232487701], length 1380
15:25:07.957499 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [.], seq 2761:4141, ack 518, win 273, options [nop,nop,TS val 3060773115 ecr 4232487701], length 1380
15:25:07.957501 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [P.], seq 4141:4970, ack 518, win 273, options [nop,nop,TS val 3060773115 ecr 4232487701], length 829
15:25:07.957580 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [.], ack 4970, win 1976, options [nop,nop,TS val 4232487739 ecr 3060773115], length 0
15:25:07.957687 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [.], ack 4970, win 2048, options [nop,nop,TS val 4232487739 ecr 3060773115], length 0
15:25:07.960236 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [P.], seq 518:576, ack 4970, win 2048, options [nop,nop,TS val 4232487741 ecr 3060773115], length 58
15:25:07.993411 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [.], ack 576, win 273, options [nop,nop,TS val 3060773152 ecr 4232487741], length 0
15:25:07.993548 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [P.], seq 576:722, ack 4970, win 2048, options [nop,nop,TS val 4232487775 ecr 3060773152], length 146
15:25:08.027521 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [.], ack 722, win 275, options [nop,nop,TS val 3060773186 ecr 4232487775], length 0
15:25:08.027523 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [P.], seq 4970:5815, ack 722, win 275, options [nop,nop,TS val 3060773187 ecr 4232487775], length 845
15:25:08.027525 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [P.], seq 5815:5839, ack 722, win 275, options [nop,nop,TS val 3060773187 ecr 4232487775], length 24
15:25:08.027526 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [F.], seq 5839, ack 722, win 275, options [nop,nop,TS val 3060773187 ecr 4232487775], length 0
15:25:08.027666 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [.], ack 5839, win 2034, options [nop,nop,TS val 4232487809 ecr 3060773187], length 0
15:25:08.027727 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [.], ack 5840, win 2034, options [nop,nop,TS val 4232487809 ecr 3060773187], length 0
15:25:08.028030 IP 192.168.100.38.53860 > 151.101.0.81.https: Flags [F.], seq 722, ack 5840, win 2048, options [nop,nop,TS val 4232487809 ecr 3060773187], length 0
15:25:08.061912 IP 151.101.0.81.https > 192.168.100.38.53860: Flags [.], ack 723, win 275, options [nop,nop,TS val 3060773220 ecr 4232487809], length 0
Actions

Also available in: Atom PDF

Like0
Like0Like0Like1Like0