From 25151b14e7f9b92a5e3629d71a9fec643c048b85 Mon Sep 17 00:00:00 2001 From: wouter bolsterlee Date: Sat, 27 Feb 2021 08:52:49 +0100 Subject: [PATCH] lib/api: Treat *.localhost as valid localhost addresses (#7412) (ref #4815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This loosens the ‘is this localhost?’ check to include *.localhost host names. This allows for clearer (hence better) names to be used in browsers, e.g. when accessing a remote syncthing instance ‘foo’ using a ssh port forward, one can use foo.localhost to remind oneself which one is which. 💡 Without these changes, Syncthing shows a ‘Host check error’ when pointing a browser at http://foo.localhost/, and with these changes, the interface loads as usual. The .localhost top level domain is a reserved top-level domain (RFC 2606): > The ".localhost" TLD has traditionally been statically defined in > host DNS implementations as having an A record pointing to the > loop back IP address and is reserved for such use. Any other use > would conflict with widely deployed code which assumes this use. > – https://tools.ietf.org/html/rfc2606 As Wikipedia puts it: > This allows the use of these names for either documentation purposes or in local testing scenarios. – https://en.wikipedia.org/wiki/.localhost On Linux systems, systemd-resolved resolves *.localhost, on purpose: https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html See also #4815, #4816. --- lib/api/api.go | 9 +++++++-- lib/api/api_test.go | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/api/api.go b/lib/api/api.go index f22b28bfb..b3ca1c590 100644 --- a/lib/api/api.go +++ b/lib/api/api.go @@ -1772,8 +1772,13 @@ func addressIsLocalhost(addr string) bool { // There was no port, so we assume the address was just a hostname host = addr } - switch strings.ToLower(host) { - case "localhost", "localhost.": + host = strings.ToLower(host) + switch { + case host == "localhost": + return true + case host == "localhost.": + return true + case strings.HasSuffix(host, ".localhost"): return true default: ip := net.ParseIP(host) diff --git a/lib/api/api_test.go b/lib/api/api_test.go index 7bd18db54..0b60e4902 100644 --- a/lib/api/api_test.go +++ b/lib/api/api_test.go @@ -995,14 +995,14 @@ func TestAddressIsLocalhost(t *testing.T) { {"[::1]:8080", true}, {"127.0.0.1:8080", true}, {"127.23.45.56:8080", true}, + {"www.localhost", true}, + {"www.localhost:8080", true}, // These are all non-localhost addresses {"example.com", false}, {"example.com:8080", false}, {"localhost.com", false}, {"localhost.com:8080", false}, - {"www.localhost", false}, - {"www.localhost:8080", false}, {"192.0.2.10", false}, {"192.0.2.10:8080", false}, {"0.0.0.0", false},