Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)
})
17 changes: 15 additions & 2 deletions osscluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading