mirror of
https://github.com/golang/go
synced 2024-11-18 08:54:45 -07:00
net: make Dial("tcp", ln.Addr().String()) work even with bad IPv6 config
Some machines can be configured (or came/come configured) in such a state that IPv6 only half works: you can bind on [::]:n but not connect back to it. This implements a fallback such that it's guaranteed that this pattern works: ln, err := Listen("tcp", ":0") ... addr := ln.Addr().String() // "[::]:n" c, err := Dial("tcp", addr) ... which is also now tested. It will first try to dial "[::]:n", as before, but if that dial fails, it will also try "0.0.0.0:n". Fixes #18806 (contains more details) Fixes #20611 (I was going to fix nacl later, but it was easy enough) Change-Id: I1107eb197e902ae8185c781ad1bc4e2bc61d1f4c Reviewed-on: https://go-review.googlesource.com/45088 Reviewed-by: Paul Marks <pmarks@google.com>
This commit is contained in:
parent
d8a7990ffa
commit
78cf0e56ce
@ -887,3 +887,21 @@ func TestCancelAfterDial(t *testing.T) {
|
||||
try()
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 18806: it should always be possible to net.Dial a
|
||||
// net.Listener().Addr().String when the listen address was ":n", even
|
||||
// if the machine has halfway configured IPv6 such that it can bind on
|
||||
// "::" not connect back to that same address.
|
||||
func TestDialListenerAddr(t *testing.T) {
|
||||
ln, err := Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
addr := ln.Addr().String()
|
||||
c, err := Dial("tcp", addr)
|
||||
if err != nil {
|
||||
t.Fatalf("for addr %q, dial error: %v", addr, err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
@ -254,6 +254,13 @@ func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addr
|
||||
ips = []IPAddr{{IP: ip}}
|
||||
} else if ip, zone := parseIPv6(host, true); ip != nil {
|
||||
ips = []IPAddr{{IP: ip, Zone: zone}}
|
||||
// Issue 18806: if the machine has halfway configured
|
||||
// IPv6 such that it can bind on "::" (IPv6unspecified)
|
||||
// but not connect back to that same address, fall
|
||||
// back to dialing 0.0.0.0.
|
||||
if ip.Equal(IPv6unspecified) {
|
||||
ips = append(ips, IPAddr{IP: IPv4zero})
|
||||
}
|
||||
} else {
|
||||
// Try as a DNS name.
|
||||
ips, err = r.LookupIPAddr(ctx, host)
|
||||
|
@ -177,6 +177,11 @@ func (sa *SockaddrInet4) copy() Sockaddr {
|
||||
|
||||
func (sa *SockaddrInet4) key() interface{} { return *sa }
|
||||
|
||||
func isIPv4Localhost(sa Sockaddr) bool {
|
||||
sa4, ok := sa.(*SockaddrInet4)
|
||||
return ok && sa4.Addr == [4]byte{127, 0, 0, 1}
|
||||
}
|
||||
|
||||
type SockaddrInet6 struct {
|
||||
Port int
|
||||
ZoneId uint32
|
||||
@ -601,6 +606,14 @@ func (f *netFile) connect(sa Sockaddr) error {
|
||||
return EISCONN
|
||||
}
|
||||
l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
|
||||
if !ok {
|
||||
// If we're dialing 127.0.0.1 but found nothing, try
|
||||
// 0.0.0.0 also. (Issue 20611)
|
||||
if isIPv4Localhost(sa) {
|
||||
sa = &SockaddrInet4{Port: sa.(*SockaddrInet4).Port}
|
||||
l, ok = net.listener[netAddr{f.proto, f.sotype, sa.key()}]
|
||||
}
|
||||
}
|
||||
if !ok || l.listenerClosed() {
|
||||
net.Unlock()
|
||||
return ECONNREFUSED
|
||||
|
Loading…
Reference in New Issue
Block a user