Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http.Server does not treat localhost as alias of 127.0.0.1 #47785

Closed
olfek opened this issue Apr 29, 2023 · 15 comments
Closed

http.Server does not treat localhost as alias of 127.0.0.1 #47785

olfek opened this issue Apr 29, 2023 · 15 comments
Labels
http Issues or PRs related to the http subsystem.

Comments

@olfek
Copy link

olfek commented Apr 29, 2023

Version

v18.14.0

Platform

Microsoft Windows NT 10.0.22621.0 x64

Subsystem

No response

What steps will reproduce the bug?

Steps to reproduce are in this comment

angular/angular-cli#25105 (comment)

How often does it reproduce? Is there a required condition?

Always. Required condition talked about in linked comment.

What is the expected behavior? Why is that the expected behavior?

No response

What do you see instead?

Server unavailable.

Additional information

No response

@VoltrexKeyva VoltrexKeyva added the http Issues or PRs related to the http subsystem. label Apr 30, 2023
@bnoordhuis
Copy link
Member

Working as intended. Newer versions of node resolve "localhost" to whatever your OS reports the address is, like ::1.

@bnoordhuis bnoordhuis closed this as not planned Won't fix, can't repro, duplicate, stale Apr 30, 2023
@olfek
Copy link
Author

olfek commented Apr 30, 2023

My hosts file looks like this

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#	127.0.0.1       localhost
#	::1             localhost
# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

Based on this hosts file, what does http.Server think localhost is?

@bnoordhuis
Copy link
Member

node -e 'dns.lookup("localhost", console.log)' will tell you. My guess is null ::1 6 - no error, ::1 and IPv6.

@olfek
Copy link
Author

olfek commented Apr 30, 2023

So I got null ::1 6


So I think this is an actual bug.

If you create the simple server mentioned here:

angular/angular-cli#25105 (comment)

then ...

Other server implementations bind to both the 127.0.0.1 address and the localhost alias when using the host localhost.

@bnoordhuis could you please confirm this for me thanks 🙂

@bnoordhuis
Copy link
Member

I can confirm that it's not a bug. Node is doing exactly what it's being told to do: bind to ::1.

@olfek
Copy link
Author

olfek commented May 1, 2023

@bnoordhuis

Ok, but this behaviour is inconsistent with other server implementations. Do you agree with this?

Therefore, I would say that although it is not a bug in the traditional sense, the fact that it does not behave as most developers would expect makes it a bug.

This inconsistency with other server implementations affected me in the way described in my original issue. Here is a brief overview.

(1) Angular CLI -> (2) Webpack Dev Server -> (3) http.Server

(1) here passes localhost (by default) which gets passed down to (3). The Angular app is now running ONLY on localhost and not 127.0.0.1 also. The Android Virtual Device (AVD) has a special address to access everything on available on the hosts loopback (127.0.0.1).

Through this special address, I'm able to access several other servers which have been bound to localhost but NOT http.Server, consequently making my Angular app inaccessible with the default ng serve command (ng = Angular CLI). I instead have to use ng serve --host 127.0.0.1.

If you search the internet, just within the Angular community, lots of developers have run into a similar problem and have resorted to using ng serve --host 0.0.0.0 as per internet recommendations. Which if you're me, would have exposed your application under development to the entire network, thanks to a badly configured firewall. (https://github.com/orgs/nodejs/discussions/47773)

@olfek
Copy link
Author

olfek commented May 1, 2023

Pseudocode for what I'm expecting

...

bind "localhost"

...

if LOOKUP(localhost) == null
    bind 127.0.0.1
else
    bind LOOKUP(localhost)

...

--- EDIT ---
Actually, I think it makes sense to always bind to 127.0.0.1 when host is localhost in addition to binding to LOOKUP(localhost)

@bnoordhuis
Copy link
Member

That's what happens. The lookup returned ::1, remember?

@olfek
Copy link
Author

olfek commented May 1, 2023

@bnoordhuis did you take a look at my pseudocode?

The .NET server implementation (Kestrel) for example has this behavior:

When localhost is specified, Kestrel attempts to bind to both IPv4 and IPv6 loopback interfaces. If the requested port is in use by another service on either loopback interface, Kestrel fails to start. If either loopback interface is unavailable for any other reason (most commonly because IPv6 isn't supported), Kestrel logs a warning.

last paragraph here

@olfek
Copy link
Author

olfek commented May 1, 2023

@bnoordhuis

can I get a second opinion from another member of the Node JS team please 🙂

@cjihrig
Copy link
Contributor

cjihrig commented May 1, 2023

can I get a second opinion from another member of the Node JS team please

Sure. I agree with @bnoordhuis

@olfek
Copy link
Author

olfek commented May 1, 2023

@cjihrig could you please explain why you think that setting the host to localhost shouldn't automatically also bind to 127.0.0.1 if it has not been configured to point to something else?

this is how other server implementations work, namely Kestrel

@cjihrig
Copy link
Contributor

cjihrig commented May 1, 2023

dns.lookup() uses whatever the operating system tells it to use. Older versions of Node gave IPv4 priority, but that is no longer the case. If you run node -e 'dns.lookup("localhost", console.log)' on Node 16, you should get 127.0.0.1, while Node 20 gives you ::1 (at least that happens on my machine which is not Windows). Similarly, if you run node -e 'dns.lookup("localhost", { family: 4 }, console.log)' you can force it to use IPv4.

namely Kestrel

Node isn't Kestrel, and if I recall correctly, Node doesn't try to bind to multiple addresses - it uses the IP address you provide, or the result of a DNS lookup.

@olfek
Copy link
Author

olfek commented May 1, 2023

Ah okay, so it is binding to ::1 because dns.lookup prioritizes IPv6, I understand.

So I'm guessing the pseudocode code for http.Server currently looks something like:

var host = "localhost"
bind LOOKUP(host) // Binds to ::1

I am proposing:

var host = "localhost"

if host == "localhost"
    bind ::1
    bind 127.0.0.1

bind LOOKUP(host) // Extra addresses other than ::1 and 127.0.0.1

This would bring it inline with developer expectations.

Node isn't Kestrel

I understand, but having used a few different server implementations, the behavior of http.Server is not as expected, resulting in
confusion and wasting of valuable time.

@rekkyrosso
Copy link

I just dockerized my app and now 127.0.0.1 works fine. And it doesn't outside of Docker. I think that this will trip more people up in the future. I have no comment about its correctness though. Beyond my expertise level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem.
Projects
None yet
Development

No branches or pull requests

5 participants