net/dnscache: try IPv6 addresses first (#5349)

Signed-off-by: Andrew Dunham <andrew@tailscale.com>

Signed-off-by: Andrew Dunham <andrew@tailscale.com>
This commit is contained in:
Andrew Dunham
2022-08-11 19:00:39 -04:00
committed by GitHub
parent 90555c5cb2
commit d942a2ff56
2 changed files with 54 additions and 0 deletions

View File

@ -523,6 +523,21 @@ func (dc *dialCall) raceDial(ctx context.Context, ips []netip.Addr) (net.Conn, e
return nil, errors.New("no IPs")
}
// Partition candidate list and then merge such that an IPv6 address is
// in the first spot if present, and then addresses are interleaved.
// This ensures that we're trying an IPv6 address first, then
// alternating between v4 and v6 in case one of the two networks is
// broken.
var iv4, iv6 []netip.Addr
for _, ip := range ips {
if ip.Is6() {
iv6 = append(iv6, ip)
} else {
iv4 = append(iv4, ip)
}
}
ips = interleaveSlices(iv6, iv4)
go func() {
for i, ip := range ips {
if i != 0 {
@ -580,6 +595,21 @@ func (dc *dialCall) raceDial(ctx context.Context, ips []netip.Addr) (net.Conn, e
}
}
// interleaveSlices combines two slices of the form [a, b, c] and [x, y, z]
// into a slice with elements interleaved; i.e. [a, x, b, y, c, z].
func interleaveSlices[T any](a, b []T) []T {
var (
i int
ret = make([]T, 0, len(a)+len(b))
)
for i = 0; i < len(a) && i < len(b); i++ {
ret = append(ret, a[i], b[i])
}
ret = append(ret, a[i:]...)
ret = append(ret, b[i:]...)
return ret
}
func v4addrs(aa []net.IPAddr) (ret []netip.Addr) {
for _, a := range aa {
ip, ok := netip.AddrFromSlice(a.IP)