-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
Description
After investigating from WSL side the following issue microsoft/WSL#10494, we found the root cause and a fix that can be made by Docker
more details added in the "Additional info" section
Reproduce
- Setup WSL with networkingMode=mirrored in the .wslconfig file
- In WSL, run docker run -d -p 8080:80 nginx:alpine
- In a Windows browser, go to localhost:8080
Expected behavior
Windows browser is able to access the nginx server running in the Docker container
docker version
Client:
Version: 24.0.7
API version: 1.43
Go version: go1.21.1
Git commit: 24.0.7-0ubuntu2~22.04.1
Built: Wed Mar 13 20:23:54 2024
OS/Arch: linux/amd64
Context: default
Server:
Engine:
Version: 24.0.7
API version: 1.43 (minimum version 1.12)
Go version: go1.21.1
Git commit: 24.0.7-0ubuntu2~22.04.1
Built: Wed Mar 13 20:23:54 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.12
GitCommit:
runc:
Version: 1.1.12-0ubuntu2~22.04.1
GitCommit:
docker-init:
Version: 0.19.0
GitCommit:
docker info
Client:
Version: 24.0.7
Context: default
Debug Mode: false
Server:
Containers: 1
Running: 1
Paused: 0
Stopped: 0
Images: 1
Server Version: 24.0.7
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version:
runc version:
init version:
Security Options:
seccomp
Profile: builtin
Kernel Version: 5.15.153.1-microsoft-standard-WSL2
Operating System: Ubuntu 22.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 7.758GiB
Name: wsl-test
ID: d62f9024-99e1-4774-8d65-b5554f8f2b11
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
WARNING: No blkio throttle.read_bps_device support
WARNING: No blkio throttle.write_bps_device support
WARNING: No blkio throttle.read_iops_device support
WARNING: No blkio throttle.write_iops_device support
Additional Info
What's the issue and root cause:
Docker uses an nftables NAT rule to implement port forwarding and the rule applies to inbound traffic arriving in Linux.
Docker assumes that 127.0.0.1 traffic is not coming from outside Linux and so the NAT rule won't be applied to this traffic. Docker has a different mechanism to do port forwarding for 127.0.0.1
In mirrored mode 127.0.0.1 traffic can come from outside Linux, when Windows and Linux communicate using 127.0.0.1 (traffic will flow through the Linux loopback0 interface), so the NAT rule will be applied to this traffic, which breaks Docker's assumption.
How does Docker’s NAT solution work today with networkingMode = NAT? Even though Windows and Linux can communicate on 127.0.0.1 using the localhost relay, 127.0.0.1 traffic will arrive in Linux on an hvsocket connection and it won't be considered inbound traffic, so the rule won't be applied to it.
Proposed fix that can be made by Docker:
Exclude inbound traffic on interface "loopback0" from being processed by the NAT rule, by modifying the rule as shown below
Original rule (second rule in the chain):
chain DOCKER {
iifname "docker0" counter packets 0 bytes 0 return
iifname != "docker0" tcp dport 8080 counter packets 0 bytes 0 dnat to 172.17.0.2:80
}
New rule (second rule in the chain):
chain DOCKER {
iifname "docker0" counter packets 0 bytes 0 return
iifname != "docker0" iifname != "loopback0" tcp dport 8080 counter packets 0 bytes 0 dnat to 172.17.0.2:80
}
Fix was tested by running "docker run -d -p 8080:80 nginx:alpine" in Linux, then connecting to localhost:8080 in a Windows browser - the scenario did not work before the fix and worked after applying the fix manually.
Risk assesment:
Risk of the fix is low
In mirrored mode, loopback0 interface is only used for 127.0.0.1 traffic. 127.0.0.1 traffic is not supposed to be processed by the NAT rule - excluding loopback0 traffic from being processed by the NAT rule should not affect existing functionality.