Skip to content

Commit 4e20e55

Browse files
committed
net: shuffle resolved addrs before sort by RFC6724 for connection load-balancing
shuffle resolved addrs before sort by RFC6724 for connection load-balancing Fixes #31698
1 parent c5c05a0 commit 4e20e55

File tree

4 files changed

+35
-10
lines changed

4 files changed

+35
-10
lines changed

src/net/dnsclient_unix.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,6 @@ func goLookupIPFiles(name string) (addrs []IPAddr, canonical string) {
595595
addrs = append(addrs, addr)
596596
}
597597
}
598-
sortByRFC6724(addrs)
599598
return addrs, canonical
600599
}
601600

@@ -607,6 +606,12 @@ func (r *Resolver) goLookupIP(ctx context.Context, network, host string, order h
607606
}
608607

609608
func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, cname dnsmessage.Name, err error) {
609+
addrs, cname, err = r.goLookupIPCNAME(ctx, network, name, order, conf)
610+
sortByRFC6724(addrs)
611+
return addrs, cname, err
612+
}
613+
614+
func (r *Resolver) goLookupIPCNAME(ctx context.Context, network, name string, order hostLookupOrder, conf *dnsConfig) (addrs []IPAddr, cname dnsmessage.Name, err error) {
610615
if order == hostLookupFilesDNS || order == hostLookupFiles {
611616
var canonical string
612617
addrs, canonical = goLookupIPFiles(name)
@@ -796,7 +801,6 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name strin
796801
// just one is misleading. See also golang.org/issue/6324.
797802
lastErr.Name = name
798803
}
799-
sortByRFC6724(addrs)
800804
if len(addrs) == 0 && !(network == "CNAME" && cname.Length > 0) {
801805
if order == hostLookupDNSFiles {
802806
var canonical string

src/net/lookup.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"internal/nettrace"
1111
"internal/singleflight"
1212
"internal/stringslite"
13+
"math/rand/v2"
1314
"net/netip"
1415
"sync"
1516

@@ -373,7 +374,18 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
373374
addrs, _ := r.Val.([]IPAddr)
374375
trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
375376
}
376-
return lookupIPReturn(r.Val, err, r.Shared)
377+
// shuffle resolved addrs before sort by RFC6724 for connection load-balancing
378+
// See https://github.com/golang/go/issues/34511
379+
// See https://github.com/grafana/loki/issues/3301
380+
// See https://github.com/grafana/loki/issues/9239
381+
// See https://github.com/restic/restic/issues/4444
382+
// See https://github.com/golang/go/issues/31698
383+
addrs, err := lookupIPReturn(r.Val, err, r.Shared)
384+
rand.Shuffle(len(addrs), func(i, j int) {
385+
addrs[i], addrs[j] = addrs[j], addrs[i]
386+
})
387+
sortByRFC6724(addrs)
388+
return addrs, err
377389
}
378390
}
379391

src/net/lookup_test.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ func TestDNSFlood(t *testing.T) {
505505

506506
defer dnsWaitGroup.Wait()
507507

508-
var N = 5000
508+
N := 5000
509509
if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
510510
// On Darwin this test consumes kernel threads much
511511
// than other platforms for some reason.
@@ -757,7 +757,7 @@ func TestLookupPort(t *testing.T) {
757757
port int
758758
ok bool
759759
}
760-
var tests = []test{
760+
tests := []test{
761761
{"tcp", "0", 0, true},
762762
{"udp", "0", 0, true},
763763
{"udp", "domain", 53, true},
@@ -809,7 +809,7 @@ func TestLookupPort_Minimal(t *testing.T) {
809809
name string
810810
port int
811811
}
812-
var tests = []test{
812+
tests := []test{
813813
{"tcp", "http", 80},
814814
{"tcp", "HTTP", 80}, // case shouldn't matter
815815
{"tcp", "https", 443},
@@ -832,7 +832,7 @@ func TestLookupProtocol_Minimal(t *testing.T) {
832832
name string
833833
want int
834834
}
835-
var tests = []test{
835+
tests := []test{
836836
{"tcp", 6},
837837
{"TcP", 6}, // case shouldn't matter
838838
{"icmp", 1},
@@ -847,7 +847,6 @@ func TestLookupProtocol_Minimal(t *testing.T) {
847847
t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want)
848848
}
849849
}
850-
851850
}
852851

853852
func TestLookupNonLDH(t *testing.T) {
@@ -1192,14 +1191,24 @@ func TestLookupIPAddrConcurrentCallsForNetworks(t *testing.T) {
11921191
t.Errorf("lookupIPAddr(%v, %v): unexpected error: %v", network, host, err)
11931192
}
11941193
wantIPs := results[[2]string{network, host}]
1195-
if !reflect.DeepEqual(gotIPs, wantIPs) {
1194+
// ingore order
1195+
if !reflect.DeepEqual(sortedIPAddrStrings(gotIPs), sortedIPAddrStrings(wantIPs)) {
11961196
t.Errorf("lookupIPAddr(%v, %v): mismatched IPAddr results\n\tGot: %v\n\tWant: %v", network, host, gotIPs, wantIPs)
11971197
}
11981198
}()
11991199
}
12001200
wg.Wait()
12011201
}
12021202

1203+
func sortedIPAddrStrings(ipAddrs []IPAddr) []string {
1204+
ret := make([]string, len(ipAddrs))
1205+
for i, ipAddr := range ipAddrs {
1206+
ret[i] = ipAddr.String() + "\000" + ipAddr.Zone
1207+
}
1208+
slices.Sort(ret)
1209+
return ret
1210+
}
1211+
12031212
// Issue 53995: Resolver.LookupIP should return error for empty host name.
12041213
func TestResolverLookupIPWithEmptyHost(t *testing.T) {
12051214
_, err := DefaultResolver.LookupIP(context.Background(), "ip", "")

src/net/lookup_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []
6363
if order == hostLookupCgo {
6464
return cgoLookupIP(ctx, network, host)
6565
}
66-
ips, _, err := r.goLookupIPCNAMEOrder(ctx, network, host, order, conf)
66+
ips, _, err := r.goLookupIPCNAME(ctx, network, host, order, conf)
6767
return ips, err
6868
}
6969

0 commit comments

Comments
 (0)