Repository navigation
opts: accept bracketed IPv6 host without a port in ParseTCPAddr - #7401
Yeagerist0 wants to merge 2 commits into
Conversation
ParseTCPAddr appends the default port by calling net.JoinHostPort on u.Host. For a bracketed IPv6 literal without a port ("tcp://[::1]") u.Host still contains the brackets, so JoinHostPort produced "[[::1]]:2375" and the address was rejected as an invalid bind address, while "[::1]:" and "::1" were both accepted.
Strip the brackets before adding the default port, and add test cases.
Signed-off-by: Hitarth Jain <180412661+Yeagerist0@users.noreply.github.com>
by-ae
left a comment
There was a problem hiding this comment.
I pulled ParseTCPAddr from af08d01 into a scratch program and ran it on some edge cases (default tcp://127.0.0.1:2375):
"[::1]" -> "tcp://[::1]:2375"
"tcp://[::1]" -> "tcp://[::1]:2375"
"[::1]/path" -> "tcp://[::1]:2375/path"
"::1" -> "tcp://[::1]:2375" (unchanged)
"[fe80::1%25eth0]" -> "tcp://[fe80::1%eth0]:2375"
"[]", "[[::1]]", "[localhost]", "[::1]x" -> still rejected by url.Parse
So the fix does what it says and doesn't loosen validation. The bracket strip only runs on the fallback path, after url.Parse has already validated the IP literal.
If anyone suggests replacing the manual strip with u.Hostname(): that would break the unbracketed form, which currently works through this same fallback. url.Parse("tcp://::1") gives Host == "::1" but Hostname() == ":". The explicit [...] check is the safer choice. A short note in the comment might stop someone "simplifying" it later.
One thing I found that this PR doesn't touch (it happens with or without it): with a zone, the returned string isn't a valid URL anymore. The input needs %25 to get past url.Parse, but the output is built with fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path) (opts/hosts.go#L149). That emits the decoded %eth0, and parsing it again fails with invalid URL escape "%et". [fe80::1%25eth0]:5555 does the same on master. That probably belongs in its own issue, not in this PR.
u.Hostname() returns ":" for the unbracketed form ("tcp://::1"), which
also goes through this fallback.
Signed-off-by: Hitarth Jain <180412661+Yeagerist0@users.noreply.github.com>
|
Thanks @by-ae, that's a useful check. I added the note about For the zone case: agreed, it's a separate bug and it's already there on master. I'll open an issue for it instead of adding it to this PR. |
Summary
docker -H tcp://[::1](a bracketed IPv6 literal with no port) is rejected withinvalid bind address format, whiletcp://[::1]:andtcp://::1are accepted and get the default port.ParseTCPAddradds the default port withnet.JoinHostPort(u.Host, defaultPort).u.Hoststill has its brackets, andJoinHostPortadds its own, so the result was[[::1]]:2375. The fix strips the brackets before adding the default port. I added[::1]and[0:0:0:0:0:0:0:1]cases toTestParseDockerDaemonHostand[::1]/[::1]/pathtoTestParseTCP; they fail without the change and pass with it. I did not run it against a live daemon.Release notes
Created with: Claude Code (Claude Sonnet 5.5). I used it to find the bug and draft the fix and tests; I reviewed the change and own it.