diff --git a/net/dnsfallback/dnsfallback.go b/net/dnsfallback/dnsfallback.go index 9039dee1e..c71cb16ba 100644 --- a/net/dnsfallback/dnsfallback.go +++ b/net/dnsfallback/dnsfallback.go @@ -30,26 +30,40 @@ func Lookup(ctx context.Context, host string) ([]netaddr.IP, error) { ip netaddr.IP } - var cands []nameIP dm := derpmap.Prod() + var cands4, cands6 []nameIP for _, dr := range dm.Regions { for _, n := range dr.Nodes { if ip, err := netaddr.ParseIP(n.IPv4); err == nil { - cands = append(cands, nameIP{n.HostName, ip}) + cands4 = append(cands4, nameIP{n.HostName, ip}) } if ip, err := netaddr.ParseIP(n.IPv6); err == nil { - cands = append(cands, nameIP{n.HostName, ip}) + cands6 = append(cands6, nameIP{n.HostName, ip}) } } } - rand.Shuffle(len(cands), func(i, j int) { - cands[i], cands[j] = cands[j], cands[i] - }) + rand.Shuffle(len(cands4), func(i, j int) { cands4[i], cands4[j] = cands4[j], cands4[i] }) + rand.Shuffle(len(cands6), func(i, j int) { cands6[i], cands6[j] = cands6[j], cands6[i] }) + + const maxCands = 6 + var cands []nameIP // up to maxCands alternating v4/v6 as long as we have both + for (len(cands4) > 0 || len(cands6) > 0) && len(cands) < maxCands { + if len(cands4) > 0 { + cands = append(cands, cands4[0]) + cands4 = cands4[1:] + } + if len(cands6) > 0 { + cands = append(cands, cands6[0]) + cands6 = cands6[1:] + } + } if len(cands) == 0 { return nil, fmt.Errorf("no DNS fallback options for %q", host) } - for ctx.Err() == nil && len(cands) > 0 { - cand := cands[0] + for _, cand := range cands { + if err := ctx.Err(); err != nil { + return nil, err + } log.Printf("trying bootstrapDNS(%q, %q) for %q ...", cand.dnsName, cand.ip, host) ctx, cancel := context.WithTimeout(ctx, 3*time.Second) defer cancel()