net: Dialer.Dial{TCP,UDP,IP} incorrectly treats invalid addresses as :: #81620
Description
Go version
go version go1.27.1-X:nodwarf5 linux/amd64
Output of go env in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v3'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN='/home/database64128/go/bin'
GOCACHE='/home/database64128/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/database64128/.config/go/env'
GOEXE=''
GOEXPERIMENT='nodwarf5'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1790460134=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/database64128/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPACKAGESDRIVER=''
GOPATH='/home/database64128/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='on'
GOTELEMETRYDIR='/home/database64128/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.27.1-X:nodwarf5'
GOWORK=''
PKG_CONFIG='pkg-config'What did you do?
Call one of the context-aware Dialer methods DialTCP, DialUDP, DialIP (introduced in #49097, Go 1.26) with zero value laddr and/or raddr.
What did you see happen?
For DialTCP, DialUDP, the zero value netip.AddrPort is treated as [::]:0.
For DialIP, the zero value netip.Addr is treated as ::.
What did you expect to see?
If raddr is the zero value, return an error, just like other dial methods and functions.
If laddr is the zero value, do not call bind(2) before connect(2). Calling bind([::]:0) forces the operating system to allocate an available ephemeral port to the socket, because it does not know whether the next call will be listen(2) or connect(2). This disables source 2-tuple reuse for TCP sockets, and will result in ephemeral port exhaustion on busy servers. Read more about it in https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/
The current implementation unconditionally calls TCPAddrFromAddrPort/UDPAddrFromAddrPort/ipAddrFromAddr on laddr and raddr, and then passes a non-nil *net.TCPAddr/*net.UDPAddr/*net.IPAddr to the old dial functions. These are equivalent to [::]:0 and causes bind(2) to be called on the socket.
This is an easy fix. Sending a CL.
Update: mailed CL 835805
Activity
gopherbot commentedon Sep 20, 2026
Change https://go.dev/cl/835805 mentions this issue:
net: fix zero value address handling in Dialer.Dial{TCP,UDP,IP}database64128 commentedon Sep 20, 2026
/cc @fraenkel
gabyhelp commentedon Sep 20, 2026
Related Issues
Related Code Changes
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
🩹 service: unconditionally set IP_BIND_ADDRESS_NO_PORT as workaround …
🐡 all: fix zero netip.AddrPort handling
prattmic commentedon Sep 29, 2026
cc @neild @nicholashusin
database64128 commentedon Oct 5, 2026
@gopherbot please open backport issues. As mentioned in the issue description, users who migrate to these new APIs could face port exhaustion issues that would result in reduced capacity or service disruption. The merged fix just adds trivial address validity checks, so the risk should be very low.
On the other hand, the easiest workaround is to simply not migrate until 1.28. But that'd be a very confusing situation, since these methods were added in Go 1.26, but then you're not supposed to use them until 1.28. A more involved workaround is to unconditionally enable
IP_BIND_ADDRESS_NO_PORT, but that's only available on Linux.gopherbot commentedon Oct 5, 2026
Backport issue(s) opened: #82022 (for 1.26), #82023 (for 1.28).
Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases.
net: fix zero value address handling in Dialer.Dial{TCP,UDP,IP}