Skip to content

net: make Dial(listener.Addr().String()) always work, even if machine's IPv6 config is not ideal #18806

@bradfitz

Description

@bradfitz

I just hit a problem in grpc-go (grpc/grpc-go#1058) where their tests were assuming they could write code like this:

        lis, err := net.Listen("tcp", ":0")
        if err != nil {
                t.Fatalf("Failed to listen: %v", err)
        }
        conn, err := net.Dial("tcp", lis.Addr().String())

The code looks reasonable, and often works (on both Go 1.7 and Go 1.8, on Linux and Darwin).

But not always.

lis.Addr().String() returns [::]:NNNNN, which looks like an IPv6 address literal for all zeros (like 0.0.0.0), regardless of whether the machine has IPv6.

And if a machine doesn't have an IPv6 address on the loopback interface, then net.Dial("tcp", "[::]:12345") fails.

But it passes otherwise.

The net.Dial documentation (https://beta.golang.org/pkg/net/#Dial) is kinda fuzzy on whether dialing the all zero address works. It does document and implement this behavior this, though:

If the host is empty, as in ":80", the local system is assumed.

Thus, the solution for gRPC's tests and anybody else is apparently adding something hacky like:

// dialAddr returns a valid net.Dial address to dial using network "tcp".
func dialAddr(ln net.Listener) string {
	addr := ln.Addr().String()
	addr = strings.TrimPrefix(addr, "[::]")
	addr = strings.TrimPrefix(addr, "0.0.0.0")
	return addr
}

But that's kinda lame and tedious.

Maybe we should just treat a net.Dial of [::] or 0.0.0.0 the same as an empty string for the host part?

/cc @mikioh @rsc @ianlancetaylor @MakMukhi

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions