Skip to content

net: ipv4 chosen first when ipv6 is available #68795

Open
@rittneje

Description

@rittneje

Go version

go version go1.22.5 darwin/amd64

Output of go env in your module/workspace:

GO111MODULE='auto'
GOARCH='amd64'
GOBIN=''
GOCACHE='/tmp/.gocache'
GOENV='/Users/rittneje/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/rittneje/test/pkg/mod'
GONOPROXY='[REDACTED]'
GONOSUMDB='[REDACTED]'
GOOS='darwin'
GOPATH='/Users/rittneje/test'
GOPRIVATE='[REDACTED]'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/rittneje/go1.22.5'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/Users/rittneje/go1.22.5/pkg/tool/darwin_amd64'
GOVCS='[REDACTED]'
GOVERSION='go1.22.5'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/rittneje/test/src/dialtest/go.mod'
GOWORK='/Users/rittneje/test/go.work'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/kf/kr7_s3xx0l12zbj3jrn082hmzy5gvy/T/go-build666976387=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

package main

import (
	"context"
	"log"
	"net"
	"net/http/httptrace"
)

func main() {
	d := &net.Dialer{}

	ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
		DNSStart: func(info httptrace.DNSStartInfo) {
			log.Printf("DNSStart: %q", info.Host)
		},
		DNSDone: func(info httptrace.DNSDoneInfo) {
			log.Printf("DNSDone: %s", info.Addrs)
		},
		ConnectStart: func(network, addr string) {
			log.Printf("ConnectStart: %s %s", network, addr)
		},
		ConnectDone: func(network, addr string, err error) {
			log.Printf("ConnectDone: %s %s %v", network, addr, err)
		},
	})

	c, err := d.DialContext(ctx, "tcp", "www.google.com:443")
	if err != nil {
		panic(err)
	}
	defer c.Close()

	log.Printf("RemoteAddr: %s", c.RemoteAddr())
}

What did you see happen?

On a network where IPv4 is blocked:

2024/08/08 16:03:47 DNSStart: "www.google.com"
2024/08/08 16:03:47 DNSDone: [{142.250.72.100 } {2607:f8b0:4006:809::2004 }]
2024/08/08 16:03:47 ConnectStart: tcp 142.250.72.100:443
2024/08/08 16:03:48 ConnectStart: tcp [2607:f8b0:4006:809::2004]:443
2024/08/08 16:03:48 ConnectDone: tcp [2607:f8b0:4006:809::2004]:443
2024/08/08 16:03:48 RemoteAddr: [2607:f8b0:4006:809::2004]:443

This shows that it incorrectly tried IPv4 first, and then fell back to IPv6.

(The above output is from running on Linux ARM with the netgo build tag, not on macos.)

What did you expect to see?

As per the documentation in net, it should follow "happy eyeballs" and dial IPv6 first, and only fall back to IPv4 if that doesn't work.

If the current behavior is intentional, then the documentation ought to be corrected.

This was previously reported in #54928 but was not fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions