Open dcarbone opened 2 weeks ago
lsof
output with sample code:
0.0.0.0
:# sudo lsof -nP -i4TCP | grep LISTEN | grep 9002
#
(results in empty output, exit code 1)
127.0.0.1
:# sudo lsof -nP -i4TCP | grep LISTEN | grep 9002
com.docke 5874 dcarbone 177u IPv4 0x7f1382407af2058d 0t0 TCP 127.0.0.1:9002 (LISTEN)
#
(results in 1 row returned, exit code 0)
I can repro this issue on the latest nightly build of Docker Desktop. I also tested it with my wip branch where I add support for v6-only and dual-stack, and I can confirm it doesn't suffer from this bug.
I'm pretty sure this bug has already been reported but I can't find the original ticket. I'll close this one as duplicate if I can get hold of it.
For DD versions released up until now, the workaround is to make sure the socket is bound to the IPv4 ANY address.
diff --git a/main.go b/main.go
index f00ac31..a21f667 100644
--- a/main.go
+++ b/main.go
@@ -25,7 +25,7 @@ func main() {
_, _ = w.Write([]byte("hellord"))
})
- if l, err = lcfg.Listen(ctx, "tcp", "0.0.0.0:9002"); err != nil {
+ if l, err = lcfg.Listen(ctx, "tcp4", "0.0.0.0:9002"); err != nil {
panic(err.Error())
}
The provided repro makes a call to ListenConfig.Listen()
, which get passed tcp
as its 2nd argument. net.Dial()
defines the semantic of that argument:
Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)
That means tcp
is dual-stack. This can be observed with strace
:
# With tcp
$ strace -f --trace=bind ./testapp
...
[pid 1615] bind(3, {sa_family=AF_INET6, sin6_port=htons(9002), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, 28) = 0
# With tcp4
$ strace -f --trace=bind ./testapp
[pid 1392] bind(3, {sa_family=AF_INET, sin_port=htons(9002), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
Description
Host Information:
I have a go binary that runs inside an Alpine container. When developing locally, this container must be run with
host
networking. On my primary Ubuntu development machine, I am able to build the listener using0.0.0.0:$PORT
or127.0.0.1:$PORT
. On this Mac that I was provided to test updates I make for Mac user compatibility, the only way I am able to get Docker Desktop to bind the host's loopback interface with the expected port(s) is to specifically bind them to127.0.0.1:$PORT
. Using0.0.0.0:$PORT
does not work.Attached is code I used to reproduce this issue in isolation: mac_dd_nethost_bind_test.zip
The original source code demonstrates what happens with
0.0.0.0:9002
as the listener bind address. This does not propagate to the host loopback interface on macos. To see a working example, you will need to edit the providedmain.go
file line 28 from0.0.0.0:9002
to127.0.0.1:9002
, rebuild and re-run.Reproduce
To see outcome of
0.0.0.0
bind:docker build -t mac_dd_nethost_test --load .
docker run --rm --net=host mac_dd_nethost_test
http://127.0.0.1:9002
To see outcome of
127.0.0.1
bind:main.go
, replacing0.0.0.0
with127.0.0.1
Expected behavior
Creating a listener that binds
0.0.0.0
should result in the in-container binds being propagated to the macos host loopback interface.docker version
docker info
Diagnostics ID
3935486C-8631-4461-B3FB-19E3AE42907D/20240708172250
Additional Info
No response