1
0
mirror of https://github.com/redis/go-redis.git synced 2025-09-02 22:01:16 +03:00

fix(client): Do not assume that all non-IP hosts are loopbacks (#3085)

* Do not assume that all non-IP hosts are loopbacks

* handle localhost and Docker internal hostnames

---------

Co-authored-by: Nedyalko Dyakov <nedyalko.dyakov@gmail.com>
Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
Co-authored-by: ofekshenawa <ofek.shenawa@redis.com>
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
This commit is contained in:
Jonathan Suever
2025-09-02 08:58:50 -04:00
committed by GitHub
parent f0058063a9
commit 6f41b600c5
2 changed files with 50 additions and 2 deletions

View File

@@ -383,3 +383,38 @@ var _ = Describe("ClusterClient", func() {
})
})
})
var _ = Describe("isLoopback", func() {
DescribeTable("should correctly identify loopback addresses",
func(host string, expected bool) {
result := isLoopback(host)
Expect(result).To(Equal(expected))
},
// IP addresses
Entry("IPv4 loopback", "127.0.0.1", true),
Entry("IPv6 loopback", "::1", true),
Entry("IPv4 non-loopback", "192.168.1.1", false),
Entry("IPv6 non-loopback", "2001:db8::1", false),
// Well-known loopback hostnames
Entry("localhost lowercase", "localhost", true),
Entry("localhost uppercase", "LOCALHOST", true),
Entry("localhost mixed case", "LocalHost", true),
// Docker-specific loopbacks
Entry("host.docker.internal", "host.docker.internal", true),
Entry("HOST.DOCKER.INTERNAL", "HOST.DOCKER.INTERNAL", true),
Entry("custom.docker.internal", "custom.docker.internal", true),
Entry("app.docker.internal", "app.docker.internal", true),
// Non-loopback hostnames
Entry("redis hostname", "redis-cluster", false),
Entry("FQDN", "redis.example.com", false),
Entry("docker but not internal", "redis.docker.com", false),
// Edge cases
Entry("empty string", "", false),
Entry("invalid IP", "256.256.256.256", false),
Entry("partial docker internal", "docker.internal", false),
)
})

View File

@@ -781,12 +781,25 @@ func replaceLoopbackHost(nodeAddr, originHost string) string {
return net.JoinHostPort(originHost, nodePort)
}
// isLoopback returns true if the host is a loopback address.
// For IP addresses, it uses net.IP.IsLoopback().
// For hostnames, it recognizes well-known loopback hostnames like "localhost"
// and Docker-specific loopback patterns like "*.docker.internal".
func isLoopback(host string) bool {
ip := net.ParseIP(host)
if ip == nil {
if ip != nil {
return ip.IsLoopback()
}
if strings.ToLower(host) == "localhost" {
return true
}
return ip.IsLoopback()
if strings.HasSuffix(strings.ToLower(host), ".docker.internal") {
return true
}
return false
}
func (c *clusterState) slotMasterNode(slot int) (*clusterNode, error) {