From 9d2ea153468b3bd774056a7e280e34bfc14bfe1f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 10 Oct 2023 15:21:37 +0700 Subject: [PATCH] internal/clientinfo: ignoring localhost entry for hostsfile mapping Otherwise, actual hostname will be overriden with "localhost", which is rather confusing/bad for UX. --- internal/clientinfo/hostsfile.go | 26 ++++++++++++++++++++- internal/clientinfo/hostsfile_test.go | 33 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 internal/clientinfo/hostsfile_test.go diff --git a/internal/clientinfo/hostsfile.go b/internal/clientinfo/hostsfile.go index 71ed090..baf05fb 100644 --- a/internal/clientinfo/hostsfile.go +++ b/internal/clientinfo/hostsfile.go @@ -10,6 +10,12 @@ import ( "github.com/Control-D-Inc/ctrld" ) +const ( + ipv4LocalhostName = "localhost" + ipv6LocalhostName = "ip6-localhost" + ipv6LoopbackName = "ip6-loopback" +) + // hostsFile provides client discovery functionality using system hosts file. type hostsFile struct { watcher *fsnotify.Watcher @@ -80,7 +86,15 @@ func (hf *hostsFile) LookupHostnameByIP(ip string) string { hf.mu.Lock() defer hf.mu.Unlock() if names := hf.m[ip]; len(names) > 0 { - return normalizeHostname(names[0]) + isLoopback := ip == "127.0.0.1" || ip == "::1" + for _, hostname := range names { + name := normalizeHostname(hostname) + // Ignoring ipv4/ipv6 loopback entry. + if isLoopback && isLocalhostName(name) { + continue + } + return name + } } return "" } @@ -94,3 +108,13 @@ func (hf *hostsFile) LookupHostnameByMac(mac string) string { func (hf *hostsFile) String() string { return "hosts" } + +// isLocalhostName reports whether the given hostname represents localhost. +func isLocalhostName(hostname string) bool { + switch hostname { + case ipv4LocalhostName, ipv6LocalhostName, ipv6LoopbackName: + return true + default: + return false + } +} diff --git a/internal/clientinfo/hostsfile_test.go b/internal/clientinfo/hostsfile_test.go new file mode 100644 index 0000000..f67fcef --- /dev/null +++ b/internal/clientinfo/hostsfile_test.go @@ -0,0 +1,33 @@ +package clientinfo + +import ( + "testing" +) + +func Test_hostsFile_LookupHostnameByIP(t *testing.T) { + tests := []struct { + name string + ip string + hostnames []string + expectedHostname string + }{ + {"ipv4 loopback", "127.0.0.1", []string{ipv4LocalhostName}, ""}, + {"ipv6 loopback", "::1", []string{ipv6LocalhostName, ipv6LoopbackName}, ""}, + {"non-localhost", "::1", []string{"foo"}, "foo"}, + {"multiple hostnames", "::1", []string{ipv4LocalhostName, "foo"}, "foo"}, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + hf := &hostsFile{m: make(map[string][]string)} + hf.mu.Lock() + hf.m[tc.ip] = tc.hostnames + hf.mu.Unlock() + if got := hf.LookupHostnameByIP(tc.ip); got != tc.expectedHostname { + t.Errorf("unpexpected result, want: %q, got: %q", tc.expectedHostname, got) + } + }) + } +}