Repository navigation
Requests to an IPv6 address result in: HTTP::ConnectionError (failed to connect: getaddrinfo: Name or service not known) #730
Description
I'm trying to use http.rb to make GET requests to IPv6 addresses and always get the following error:
HTTP::ConnectionError (failed to connect: getaddrinfo: Name or service not known)
I've tried with and without brackets around the IP address and the results are the same. (I'd expect the version without brackets to fail, so that by itself isn't a problem. More detail on why I'm even trying a bracket-less version below.)
Interestingly, making a request to the exact same URL with httparty succeeds when using the bracketed form.
Here is a demonstration of what I see using the IPv6 address for example.com (2606:2800:220:1:248:1893:25c8:1946):
http.rb without brackets:
irb(main):177:0> HTTP.get("http://2606:2800:220:1:248:1893:25c8:1946/foo?bar=baz")
Traceback (most recent call last):
15: from script/rails:6:in `<main>'
14: from script/rails:6:in `require'
13: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands.rb:41:in `<top (required)>'
12: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands/console.rb:8:in `start'
11: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands/console.rb:47:in `start'
10: from (irb):177
9: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/chainable.rb:20:in `get'
8: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/chainable.rb:77:in `request'
7: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/client.rb:30:in `request'
6: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/client.rb:67:in `perform'
5: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/client.rb:67:in `new'
4: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/connection.rb:43:in `initialize'
3: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/timeout/null.rb:21:in `connect'
2: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/timeout/null.rb:21:in `open'
1: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/timeout/null.rb:21:in `initialize'
HTTP::ConnectionError (failed to connect: getaddrinfo: Name or service not known)
http.rb with brackets:
irb(main):178:0> HTTP.get("http://[2606:2800:220:1:248:1893:25c8:1946]/foo?bar=baz")
Traceback (most recent call last):
16: from script/rails:6:in `<main>'
15: from script/rails:6:in `require'
14: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands.rb:41:in `<top (required)>'
13: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands/console.rb:8:in `start'
12: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands/console.rb:47:in `start'
11: from (irb):178
10: from (irb):178:in `rescue in irb_binding'
9: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/chainable.rb:20:in `get'
8: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/chainable.rb:77:in `request'
7: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/client.rb:30:in `request'
6: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/client.rb:67:in `perform'
5: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/client.rb:67:in `new'
4: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/connection.rb:43:in `initialize'
3: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/timeout/null.rb:21:in `connect'
2: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/timeout/null.rb:21:in `open'
1: from /redacted/vendor/bundle/ruby/2.6.0/gems/http-3.3.0/lib/http/timeout/null.rb:21:in `initialize'
HTTP::ConnectionError (failed to connect: getaddrinfo: Name or service not known)
httparty without brackets:
irb(main):179:0> HTTParty.get("http://2606:2800:220:1:248:1893:25c8:1946/foo?bar=baz")
Traceback (most recent call last):
16: from script/rails:6:in `<main>'
15: from script/rails:6:in `require'
14: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands.rb:41:in `<top (required)>'
13: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands/console.rb:8:in `start'
12: from /redacted/vendor/bundle/ruby/2.6.0/gems/railties-3.2.22.30/lib/rails/commands/console.rb:47:in `start'
11: from (irb):179
10: from (irb):179:in `rescue in irb_binding'
9: from /redacted/vendor/bundle/ruby/2.6.0/gems/httparty-0.16.2/lib/httparty.rb:601:in `get'
8: from /redacted/vendor/bundle/ruby/2.6.0/gems/httparty-0.16.2/lib/httparty.rb:489:in `get'
7: from /redacted/vendor/bundle/ruby/2.6.0/gems/httparty-0.16.2/lib/httparty.rb:563:in `perform_request'
6: from /redacted/vendor/bundle/ruby/2.6.0/gems/httparty-0.16.2/lib/httparty.rb:563:in `new'
5: from /redacted/vendor/bundle/ruby/2.6.0/gems/httparty-0.16.2/lib/httparty/request.rb:63:in `initialize'
4: from /redacted/vendor/bundle/ruby/2.6.0/gems/httparty-0.16.2/lib/httparty/request.rb:73:in `path='
3: from /opt/rubies/ruby-2.6/lib/ruby/2.6.0/uri/common.rb:234:in `parse'
2: from /opt/rubies/ruby-2.6/lib/ruby/2.6.0/uri/rfc3986_parser.rb:73:in `parse'
1: from /opt/rubies/ruby-2.6/lib/ruby/2.6.0/uri/rfc3986_parser.rb:67:in `split'
URI::InvalidURIError (bad URI(is not URI?): "http://2606:2800:220:1:248:1893:25c8:1946/foo?bar=baz")
httparty with brackets:
irb(main):180:0> HTTParty.get("http://[2606:2800:220:1:248:1893:25c8:1946]/foo?bar=baz")
=> #<HTTParty::Response:0x7f257239b888 parsed_response="<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\t<head>\n\t\t<title>404 - Not Found</title>\n\t</head>\n\t<body>\n\t\t<h1>404 - Not Found</h1>\n\t</body>\n</html>\n", @response=#<Net::HTTPNotFound 404 Not Found readbody=true>, @headers={"content-type"=>["text/html"], "date"=>["Sat, 19 Nov 2022 01:56:17 GMT"], "server"=>["ECS (dab/DC47)"], "content-length"=>["345"], "connection"=>["close"]}>
I realize I'm using old versions of both HTTP libraries as well as Rails (working with a large corporate codebase that's very outdated), but I've also tried this with http.rb v5 in a Pry session outside of the context of this project, and the same error occurs.
Normally I would just use httparty, because it works, but unfortunately I can't because of a bad interaction between httparty and the newrelic_rpm gem. Apparently Net::HTTP needs brackets removed from IPv6 addresses, so httparty has some code that intentionally removes the brackets before handing off the request to Net::HTTP. At this point, New Relic instrumentation hooks into the request, attempts to re-parse the URL using the addressable gem, and raises an exception because it requires brackets around IPv6 addresses. None of this is http.rb's fault, I'm just mentioning it for the context as to why I'm trying use http.rb in the first place. I wanted to try something that doesn't use Net::HTTP under the hood so that there's no conflict in support for brackets around IPv6 addresses. I see that both http.rb and newrelic_rpm use the addressable gem for URLs, so they should be compatible.
Any idea why I'm getting this error from http.rb? I wasn't able to find documentation or issues that specifically mention IPv6 to see examples of how it's supposed to work or how to troubleshoot.
Thank you for your time.
Activity
tarcieri commentedon Nov 20, 2022
For starters:
The path shows
http-3.3.0, or v3.3.0. The latest release is 5.1.0.Can you upgrade to the latest release and see if the problem persists?
hvaghani221 commentedon Nov 25, 2022
I can verify that problem persists with http (5.1.0)
jeraki commentedon Nov 28, 2022
Yes, I mentioned this in my original post:
I apologize if that wasn't more clear.
tarcieri commentedon Nov 28, 2022
The backtrace of the error when using v5.1.0 would be helpful.
FWIW it's probably erroring out here:
https://github.com/httprb/http/blob/f4fb336/lib/http/timeout/null.rb#L21
...in which case it would be helpful to instrument it with what's being passed as
host, and figure out what it should be instead, as the ultimate error is:jeraki commentedon Nov 28, 2022
I checked out the Git repo and tried to make the request from
bundle consoleto get a stack trace with the latest version:That's with Ruby 2.6.7 (the main application I work on still uses Ruby 2.6). I can try it with a newer version of Ruby if you think that might matter.
jeraki commentedon Nov 28, 2022
I tried modifying the
connectmethod inlib/http/timeout/null.rbto this:And then when making the request in
bundle consoleI see this just before the exception and stack trace:Looks like it's seeing the last section of the address as the port.
jeraki commentedon Nov 28, 2022
Forgot to mention, here's the debug output if I put brackets around the IP address. It correctly identifies the host and port, but still results in the same exception:
tarcieri commentedon Nov 28, 2022
I've confirmed in this case that
URI#hostreturns[2606:2800:220:1:248:1893:25c8:1946]So I'm guessing the solution is we need to strip the outer brackets in this case, if the inner address is a valid IPv6 address?
jeraki commentedon Nov 28, 2022
I tried changing the
connectmethod to strip the brackets (naively, there's probably a safer way) and that gets further but raises a different exception.Connect:
Usage:
This might be an issue with IPv6 support on my local network, though. I notice that I get the same error with curl too:
tarcieri commentedon Nov 28, 2022
Stripping the brackets is probably the right solution, although you'd want a regex that matches the outer brackets with an inner capture group for valid IPv6 addresses, which if it matches returns the inner capture group.
If you can test that solution where you have IPv6 connectivity, that'd be great.
Perhaps we could test against
::1when available?jeraki commentedon Nov 29, 2022
I tried the above change to
connectby monkey patching the class in a Rails console on the server I usually work from and I was able to successfully make a request to an internal IPv6 address that was previously causing the reported error. So it does look like stripping the brackets is the fix!Strip brackets from IPv6 addresses before passing them to a socket.
hvaghani221 commentedon Dec 15, 2022
Hi @jeraki @tarcieri is there any update on this?
jeraki commentedon Dec 16, 2022
@harshit-splunk I didn't have time to work on my PR for a few weeks, but I just pushed a commit to move it forward. You can follow #731 for updates.
Strip brackets from IPv6 addresses in `HTTP::URI` (#731)