net/dnsfallback: fix infinite loop and limit number of candidates
Updates (fixes the DNS spin part, but other things aren't ideal there)
@@ -30,26 +30,40 @@ type nameIP struct {
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()
