diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDns.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDns.kt index 5e442efee4..126c3587e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDns.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDns.kt @@ -296,8 +296,10 @@ class SurgeDns( * already lowercased. */ private fun isLoopbackHostname(host: String): Boolean { - if (host == "localhost" || host.endsWith(".localhost")) return true - val literal = parseIpLiteral(host) ?: return false + // RFC 1034: a trailing dot is the FQDN form (e.g. `localhost.`), still the same name. + val name = host.trimEnd('.') + if (name == "localhost" || name.endsWith(".localhost")) return true + val literal = parseIpLiteral(name) ?: return false return literal.isLoopbackAddress || literal.isAnyLocalAddress } diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDnsTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDnsTest.kt index 692116756a..d2578126b9 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDnsTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/okhttp/SurgeDnsTest.kt @@ -540,6 +540,15 @@ class SurgeDnsTest { assertEquals(listOf(ip("127.0.0.1")), dns.lookup("relay.localhost")) } + @Test + fun `trailing-dot FQDN form of localhost keeps loopback answers`() { + // RFC 1034: `localhost.` is the same name as `localhost`, just in FQDN form. + val upstream = CountingDns(mapOf("localhost." to listOf(ip("127.0.0.1")))) + val dns = SurgeDns(delegate = upstream) + + assertEquals(listOf(ip("127.0.0.1")), dns.lookup("localhost.")) + } + @Test fun `ipv4 loopback literal keeps loopback answers`() { val upstream = CountingDns(mapOf("127.0.0.1" to listOf(ip("127.0.0.1"))))