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

Localhost relay does not support dual-mode sockets #4851

Open
justinbarclay opened this issue Jan 27, 2020 · 44 comments
Open

Localhost relay does not support dual-mode sockets #4851

justinbarclay opened this issue Jan 27, 2020 · 44 comments

Comments

@justinbarclay
Copy link

Your Windows build number: (Type ver at a Windows Command Prompt)

Microsoft Windows [Version 10.0.19551.1005]

What you're doing and what's happening:

I am trying to start-up a webserver and have it listen on a specific port. Then when I try to reach this website using a service like localtest.me it says it's unreachable, this is specifically happening when I try to run shadow-cljs on WSL2. If I run it on a WSL distro it works fine. After some talking with the author of that package I was able to boil down a reproducible issue to:

  1. In a fresh instance of Ubuntu with WSL2 enabled run nc :: 8080 -l
  2. Try to connect to nc, on Windows with any browser, at the address 127.0.0.1:8080.

What's wrong / what should be happening instead:

When opening up a server and telling it to listen on '::' and port 8080, the server becomes unreachable on the Windows side when trying to access it through a browser on 127.0.0.1:8080. However, the server is reachable through the browser when accessing it through localhost:8080. This workflow used to work on WSL1. I have tested this on a multitude of ports and it never works.

Additionally, this works fine if I use nc 0.0.0.0 8080 -l instead. It is reachable by browser on 127.0.0.1 and localhost.

@justinbarclay justinbarclay changed the title Issue connecting to webservers bound to "::" through 127.0.0.1 Problem connecting to servers bound to "::" through 127.0.0.1 Jan 27, 2020
@therealkenc
Copy link
Collaborator

Try to connect to nc, on Windows with any browser, at the address 127.0.0.1:8080.

Right; you aren't listening on ipv4 127.0.0.1 in your repro.

image

If you try to connect to 127.0.0.1:8080 on the linux side, the Linux kernel routes those (different) protocols automatically. The Windows->WSL ipv4 127.0.0.1 tunnel, notsomuch.

on Windows with any browser

No; MS Edge and Chrome treat the string localhost differently (Edge favors resolving localhost to ipv4 over ipv6 AFAICT). The client (a browser or otherwise) matters. Your browser tried connecting on ipv6, because that's how localhost resolved.

Ref ongoing #4353 et al. Work-around for the time being: Use the real ipv4 subnet to listen. That can be ever-popular 0.0.0.0, or an ipv4 subnet that is routable from Windows. For example, listen on 127.0.0.1 or (for me atm) 192.168.181.47 or 192.168.181.0. Connect using an ip4 address (contrast an ipv6 address).

@justinbarclay
Copy link
Author

I wasn't sure if it was the same root cause as #4353, so I figured it was worth posting. Thank you for the response and work arounds.

@therealkenc
Copy link
Collaborator

I wasn't sure if it was the same root cause as #4353

Your OP is fair game. #4353 was actually deemed addressed in August. I just don't have the heart to close it. There is more than one "root cause" in that ongoing thread (contrast the original post). Appreciate the submission.

@mogzol
Copy link

mogzol commented Feb 20, 2020

Ran into this same issue trying to run an express server in wsl2. If you're using hostnames from your hosts file, a quick workaround is to just change them to point to your local IPv6 address instead of the v4 one, so 127.0.0.1 mysite.dev becomes ::1 mysite.dev.

@therealkenc
Copy link
Collaborator

therealkenc commented Jun 7, 2020

Tag needs-investigation in the sense this needs a ruling on whether the current (circa 19640) behavior of the magic WSL localhost tunnel is by-design (by fiat), or should route ipv4 127.0.0.1 to ipv6 ::1 automatically like it does on Linux. I suspect but can't prove there is an IETF RFC that defines the behavior (because there's an IETF RFC for everything) but I didn't look it up.

The OP up top is sound, although you'll be better off using win32 curl.exe 127.0.0.1 to avoid ambiguity 'Edge'. New Edge (and Chrome) will look like there is no problem because it resolves localhost to ::1.

image

@therealkenc therealkenc added the needs-investigation likely actionable and/or needs more investigation label Jun 7, 2020
@curry684
Copy link

curry684 commented Jun 8, 2020

I just spent some time looking into issues I think are related to this. I have a NodeJS project in WSL2 opening a TCP/4000 server. Inside the WSL Bash I see it correctly binding:

$ netstat -apn | grep 4000
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp6       0      0 :::4000                 :::*                    LISTEN      1771/node

Running netstat -a -p -n in cmd.exe however paints a slightly different picture:

  TCP    [::1]:4000             [::]:0                 LISTENING       9140

Somehow the global binding inside wsl.exe translates to a ::1 binding in wslhost.exe (PID 9140).

Even more curious, when I use Docker Desktop WSL2 to launch an Nginx container with -p 80:80 it looks like this:

  TCP    [::]:80                [::]:0                 LISTENING       23396
  TCP    [::1]:80               [::]:0                 LISTENING       9140

So for some reason wslhost.exe is only providing the loopback bindings, and com.docker.backend.exe is forwarding it to the network.

Why does wslhost constrain the global binding to loopback itself?

@sorenwacker
Copy link

This came up recently here too. Build:

Version 10.0.19042 Build 19042

@zacharyw
Copy link

zacharyw commented Nov 16, 2021

This continues to be an issue, and the only consistent solution I've found so far is this: https://abdus.dev/posts/fixing-wsl2-localhost-access-issue/

It's a little involved and requires you to use a differently named host than localhost, but it works. Essentially this sets up a task to be triggered when wsl starts which gets the dynamic IP address of the wsl2 instance and then adds it to your windows host file under the name wsl.

So let's say you have an application you normally access in wsl2 by going to localhost:8080 in your browser. After setting up this script you would go to wsl:8080.

You'd need to tweak any services that try to hit the thing running in the wsl2 instance to use this new wsl endpoint instead of localhost.

@juanchobuiles
Copy link

Tuve un problema con el servidor Golang HTTP escuchando IPv6 :::3010 dentro de la máquina WSL2 Ubuntu.

No puedo alcanzarlo como 127.0.0.1:3010 desde mi Windows 10 y resolví el problema al redirigir la dirección IPv4 a IPv6:

netsh interface portproxy add v4tov6 listenaddress=127.0.0.1 listenport=3010 connectaddress=::1 connectport=3010

El software CurrPorts fue realmente útil para investigar cosas en Windows.

Y ese comando me ayudó a entender la situación de Ubuntu:

sudo netstat -tulpn | grep LISTEN

it worked for me

@treysis
Copy link

treysis commented Apr 20, 2022

I believe you can get IPv6 with a public address if you advertise a prefix on the virtual WSL network adapter from within Windows. Then you'd have to instruct your router to route that prefix to your Windows host. While advertising can be set up with netsh, I am not aware that Windows can request a prefix from the upstream router. So manual setup of the routing table is required. Since many people are given dynamic prefixes, this is a bit cumbersome.

@pmartincic
Copy link
Collaborator

Reading the original bug filed I'm going to close this as by design.

ipv6 and ipv4 bindings are separate. (Except maybe for RFC 4291)

@timriker
Copy link

timriker commented Mar 2, 2023

The original request tries to listen on :: 8080 which WORKS.

They they try to connect to :: 8080 from windows, which does NOT work, but should.

If they try to connect to localhost:8080 this WORKS, but is unexpected.

This still sounds like a bug to me. If the windows Hyper-V it NATting ipv4 traffic and routing 127.0.0.1 to WSL listening services, it should also NAT ipv6 and route ::1 traffic to WSL listening services.

fc00::/7 address space is set aside as unique local addresses. IMHO, WSL should use some of this space through the Hyper-V network adapter just as it uses 172.16/12

https://en.wikipedia.org/wiki/Unique_local_address

Developing and supporting IPv6 capable software under WSL is impossible currently as there is no IPv6 support under WSL. Please fix.

@pmartincic
Copy link
Collaborator

pmartincic commented Mar 2, 2023

Concerning the original bug as written. Binding on :: 8080 (ipv6 wildcard) on the guest. They describe being unable to connect via 127.0.0.1:8080 (ipv4) on the host using the relay. This is expected. They then describe being able to connect via localhost:8080 in the browser on the host. This relies on implementation specific behavior in the browser on the host where it can connect to 127.0.01 or ::1 depending on what it feels like.

@timriker
Copy link

timriker commented Mar 2, 2023

Note: Running Hyper-V Manager as Administrator, and then in Virtual Switch Manager edit the WSL switch and connect it to "External Network" and an ethernet adapter on the host, gets you ipv4 and ipv6 connectivity if that exists on the host network.

My ideal would be to have dual adapters inside WSL2. One that is NAT connected to the host, with RFC1918 addresses for IPv4 and fc00::/7 NATted ipv6 space. Then, if we're on Ethernet, an additional interface that is bridged to the host ethernet and gets it's own, perhaps public, IPv4 and IPv6 addresses from that network.

Doing this on WiFi has the issue that adding an additional MAC won't work in many cases, but it does work well on ethernet.

Two valid methods of getting WSL2 online with IPv6 as well as existing IPv4. No kernel change required, just setting up Hyper-V networks. I don't know that Hyper-V supports NAT on ipv6. I've not gotten that working, but it does support bridging with IPv4 and IPv6.

@treysis
Copy link

treysis commented Mar 2, 2023

@timriker IMHO the best would be if the host could request a prefix via DHCPv6-PD and then route this to the WSL2 instance.

@timriker
Copy link

timriker commented Mar 2, 2023

@timriker IMHO the best would be if the host could request a prefix via DHCPv6-PD and then route this to the WSL2 instance.

Yes, if the host can get a prefix, then use that. If it cannot, then fall back to NAT on fc00::/7

@pmartincic pmartincic self-assigned this Mar 3, 2023
@pmartincic pmartincic changed the title Problem connecting to servers bound to "::" through 127.0.0.1 Localhost relay does not support dual-mode sockets Mar 3, 2023
@pmartincic pmartincic reopened this Mar 3, 2023
@pmartincic
Copy link
Collaborator

pmartincic commented Mar 3, 2023

I'm re-opening this to keep track of the lack of support for dual-mode sockets in the localhost relay as indicated by the original bug. Any other issues should go to separate bugs.

@asleepace
Copy link

What worked for me was editing my .wslconfig file and commenting out the following:

  • localhostforwarding=true
  • networkingMode=mirrored
  • hostAddressLoopback=true

Then running the following from PowerShell

wsl --shutdown

Here is my full configuration

# Settings apply across all Linux distros running on WSL 2
[wsl2]

# (CAUSED ISSUE) Turn on default connection to bind WSL 2 localhost to Windows localhost
# localhostforwarding=true

# (CAUSED ISSUE) Switch networking mode to mirrored
#networkingMode=mirrored
#hostAddressLoopback=true

# Disables nested virtualization
nestedVirtualization=false

# Turns on output console showing contents of dmesg when opening a WSL 2 distro for debugging
debugConsole=true

# Enable experimental features
[experimental]
sparseVhd=true

@chanpreetdhanjal

This comment was marked as outdated.

@pmartincic
Copy link
Collaborator

Hello folks. We don't need logs for this bug. Sorry for the confusion! We are able to reproduce it and know the source of the issue. It's just a question of priorities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests