Re: Node.js - having a problem with http lib connecting to IPv6 / localhost

1,062 views
Skip to first unread message

Bert Belder

unread,
Mar 5, 2013, 4:45:48 PM3/5/13
to nod...@googlegroups.com
On Tuesday, March 5, 2013 5:58:06 PM UTC+1, Brian Hunt wrote:
I posted a question on stackoverflow detailing a problem I have encountered. The question is here:


Unfortunately none of the answers have been helpful, so I am linking to it from here. The problem is this:

I am getting Error: { [Error: connect ECONNREFUSED] code: 'ECONNREFUSED', errno: 'ECONNREFUSED', syscall: 'connect' } whenever I try to connect using the http lib to an IPv6 address alias for localhost. My hosts is:

127.0.0.1   localhost myhost.local myhost
255.255.255.255 broadcasthost
::1             localhost myhost.local myhost
fe80::1%lo0 localhost myhost.local myhost
I am running a Python server bound to myhost.local on ::1.8080.

Calling require('http').get('http://myhost.local:8080', ...) throws the above connect ECONNREFUSED.

It has been no trouble connecting to the host from other programs, such as telnet or wget.

I won't repeat all the details from the stackoverflow post, but there is some more information there that may help illustrate the problem.

I would be very grateful for any thoughts and suggestions.

Many thanks.

Brian

On your system "myhost.local" resolves to three different addresses (127.0.0.1, ::1, and fe80::1). Node prefers ipv4 over ipv6 so it'll try to connect to 127.0.0.1. Nothing is listening on 127.0.0.1:8080 so the connect() syscall fails with ECONNREFUSED. Node doesn't retry with any of the other resolved IPs - it just reports the error to you. A simple solution would be to replace 'localhost' by the intended destination ip address, '::1'.

Whether this behavior is right is somewhat open for debate, but this is what causes it.

- Bert

Brian Hunt

unread,
Mar 6, 2013, 7:14:44 AM3/6/13
to nod...@googlegroups.com
Thanks Bert.

I am sorry but I failed to mention that I had tried every permutation of the hosts file with a myhost.local. Although obvious, it is good that you point it out - sometimes the most obvious things are overlooked. :) 

With a /etc/hosts file of

127.0.0.1   localhost 
255.255.255.255 broadcasthost
::1             localhost myhost.local myhost
fe80::1%lo0 localhost
Node still refuses to connect to myhost.local on ::1.

I rooted through Node's http.js but it wasn't obvious what was doing the name resolution - name resolution seemed to be in the socket code, but I didn't know the code well enough to locate it efficiently.

Cheers,
Brian

Bert Belder

unread,
Mar 6, 2013, 7:45:49 AM3/6/13
to nod...@googlegroups.com


On Wednesday, March 6, 2013 1:14:44 PM UTC+1, Brian Hunt wrote:
I am sorry but I failed to mention that I had tried every permutation of the hosts file with a myhost.local. Although obvious, it is good that you point it out - sometimes the most obvious things are overlooked. :) 


Can you post the output of this snippet:

```
require('dns').lookup('myhost.local', console.log)
```

Brian Hunt

unread,
Mar 6, 2013, 8:32:11 AM3/6/13
to nod...@googlegroups.com
Thanks for the follow-up Brett.

> require('dns').lookup('myhost.local', console.log)
{ oncomplete: [Function: onanswer] }
> null '127.0.0.1' 4

This seems to be the heart of the issue, right there.

As a matter of interest, here are some commands that may give a little illumination:

$ wget myhost.local:8080
...
Resolving myhost.local... 127.0.0.1, ::1, fe80::1
Connecting to myhost.local|::1|:8080... connected.
...

The multiple addresses flow from getaddrinfo, if I recall correctly.

Since the node.js docs indicate that dns.lookup uses getaddrinfo, I also tried it out in Python:

$ python
>>> import socket
>>> socket.getaddrinfo("myhost.local", 8080)
[(30, 2, 17, '', ('::1', 8080, 0, 0)), (30, 1, 6, '', ('::1', 8080, 0, 0)), (2, 2, 17, '', ('127.0.0.1', 8080)), (2, 1, 6, '', ('127.0.0.1', 8080)), (30, 2, 17, '', ('fe80::1%lo0', 8080, 0, 1)), (30, 1, 6, '', ('fe80::1%lo0', 8080, 0, 1))]

This mirrors what we saw with wget.

It would seem that there are two issues at work:
 1. getaddrinfo is returning IPv4 addresses even though the name `myhost.local` is tied only to an IPv6 address in /etc/hosts; and
 2. node.js prefers the IPv4 address, and does not fallback to the alternatives upon a connection error.

Does that seem to be about right?

If this is the case, I am somewhat at a loss as to how to get conveniently Node.js to connect using the IPv6 address. A somewhat inconvenient way would be to manually parse the URL, then lookup the hosts with dns.resolve4/6, and try them all in turn.

Many thanks & cheers

Brian Hunt

unread,
Mar 6, 2013, 8:33:00 AM3/6/13
to nod...@googlegroups.com
*Bert. Thanks for the reply, Bert. :) (sorry!)


On Wednesday, 6 March 2013 07:45:49 UTC-5, Bert Belder wrote:

Bert Belder

unread,
Mar 6, 2013, 11:54:53 AM3/6/13
to nod...@googlegroups.com


On Wednesday, March 6, 2013 2:32:11 PM UTC+1, Brian Hunt wrote:
It would seem that there are two issues at work:
 1. getaddrinfo is returning IPv4 addresses even though the name `myhost.local` is tied only to an IPv6 address in /etc/hosts; and

The probably cause for this is an error on your end. Maybe you forgot to save the file, or your libc implementation caches /etc/hosts somehow and you have to flush it?
  
 2. node.js prefers the IPv4 address, and does not fallback to the alternatives upon a connection error.

If you really run into problems due to this, you might wrap the net.connect function with your own implementation. Just call the dns functions yourself and try to connect to reported addresses one by one.

As I said, I'm willing to consider changing node's behaviour here (atleast there should be a getaddrinfo wrapper that returns more that just the first result) - but that'd be post node-0.10 effort and hence is atleast a couple of months away.
(Ben / Isaac, thoughts on this?)

- Bert

Ben Noordhuis

unread,
Mar 6, 2013, 1:07:20 PM3/6/13
to nod...@googlegroups.com
Agreed on the getaddrinfo() wrapper.

Brian Hunt

unread,
Mar 6, 2013, 7:33:38 PM3/6/13
to nod...@googlegroups.com
Many thanks, Bert.  I appreciate your taking the time to get to the bottom of this.

It is likely astute to suspect a caching issue. Mac OS X is known, in my experience, for having wonky DNS caching at times. 

In due course, the getaddrinfo wrapper you suggest would be quite valuable in situations such as this.

Best,
Brian
Reply all
Reply to author
Forward
0 new messages