diff --git a/lib/private/Http/Client/DnsPinMiddleware.php b/lib/private/Http/Client/DnsPinMiddleware.php index b031f3f32366f..cb868aa7cb51f 100644 --- a/lib/private/Http/Client/DnsPinMiddleware.php +++ b/lib/private/Http/Client/DnsPinMiddleware.php @@ -25,6 +25,17 @@ public function __construct( ) { } + /** + * DNS lookups must end with a dot to be marked as + * FQDN. Otherwise, a record without answer may trigger + * a lookup on the local domain name. See GitHub + * issue #56489 for details. + */ + private function enforceFqdn(string $hostname): string { + $trimmedHostname = rtrim($hostname, '.'); + return "$trimmedHostname."; + } + /** * Fetch soa record for a target */ @@ -35,7 +46,7 @@ private function soaRecord(string $target): ?array { $second = array_pop($labels); $hostname = $second . '.' . $top; - $responses = $this->dnsGetRecord($hostname, DNS_SOA); + $responses = $this->dnsGetRecord($this->enforceFqdn($hostname), DNS_SOA); if ($responses === false || count($responses) === 0) { return null; @@ -68,7 +79,7 @@ private function dnsResolve(string $target, int $recursionCount) : array { continue; } - $dnsResponses = $this->dnsGetRecord($target, $dnsType); + $dnsResponses = $this->dnsGetRecord($this->enforceFqdn($target), $dnsType); if ($dnsResponses !== false && count($dnsResponses) > 0) { foreach ($dnsResponses as $dnsResponse) { if (isset($dnsResponse['ip'])) { diff --git a/tests/lib/Http/Client/DnsPinMiddlewareTest.php b/tests/lib/Http/Client/DnsPinMiddlewareTest.php index 790206a94220a..2699e609c5e5a 100644 --- a/tests/lib/Http/Client/DnsPinMiddlewareTest.php +++ b/tests/lib/Http/Client/DnsPinMiddlewareTest.php @@ -61,7 +61,7 @@ static function (RequestInterface $request, array $options) { ->method('dnsGetRecord') ->willReturnCallback(function (string $hostname, int $type) { // example.com SOA - if ($hostname === 'example.com') { + if ($hostname === 'example.com.') { return match ($type) { DNS_SOA => [ [ @@ -76,7 +76,7 @@ static function (RequestInterface $request, array $options) { } // example.com A, AAAA, CNAME - if ($hostname === 'www.example.com') { + if ($hostname === 'www.example.com.') { return match ($type) { DNS_A => [], DNS_AAAA => [], @@ -93,7 +93,7 @@ static function (RequestInterface $request, array $options) { } // example.net SOA - if ($hostname === 'example.net') { + if ($hostname === 'example.net.') { return match ($type) { DNS_SOA => [ [ @@ -108,7 +108,7 @@ static function (RequestInterface $request, array $options) { } // example.net A, AAAA, CNAME - if ($hostname === 'www.example.net') { + if ($hostname === 'www.example.net.') { return match ($type) { DNS_A => [ [ @@ -154,7 +154,7 @@ static function (RequestInterface $request, array $options) { ->method('dnsGetRecord') ->willReturnCallback(function (string $hostname, int $type) { // example.com SOA - if ($hostname === 'example.com') { + if ($hostname === 'example.com.') { return match ($type) { DNS_SOA => [ [ @@ -169,7 +169,7 @@ static function (RequestInterface $request, array $options) { } // example.com A, AAAA, CNAME - if ($hostname === 'www.example.com') { + if ($hostname === 'www.example.com.') { return match ($type) { DNS_A => [], DNS_AAAA => [], @@ -186,7 +186,7 @@ static function (RequestInterface $request, array $options) { } // example.net SOA - if ($hostname === 'example.net') { + if ($hostname === 'example.net.') { return match ($type) { DNS_SOA => [ [ @@ -201,7 +201,7 @@ static function (RequestInterface $request, array $options) { } // example.net A, AAAA, CNAME - if ($hostname === 'www.example.net') { + if ($hostname === 'www.example.net.') { return match ($type) { DNS_A => [ [ @@ -378,7 +378,7 @@ static function (RequestInterface $request, array $options): void { ->method('dnsGetRecord') ->willReturnCallback(function (string $hostname, int $type) { // example.com SOA - if ($hostname === 'example.com') { + if ($hostname === 'example.com.') { return match ($type) { DNS_SOA => [ [ @@ -393,7 +393,7 @@ static function (RequestInterface $request, array $options): void { } // example.com A, AAAA, CNAME - if ($hostname === 'www.example.com') { + if ($hostname === 'www.example.com.') { return match ($type) { DNS_A => [], DNS_AAAA => [], @@ -410,7 +410,7 @@ static function (RequestInterface $request, array $options): void { } // example.net SOA - if ($hostname === 'example.net') { + if ($hostname === 'example.net.') { return match ($type) { DNS_SOA => [ [ @@ -425,7 +425,7 @@ static function (RequestInterface $request, array $options): void { } // example.net A, AAAA, CNAME - if ($hostname === 'www.example.net') { + if ($hostname === 'www.example.net.') { return match ($type) { DNS_A => [ [ @@ -496,7 +496,7 @@ static function (RequestInterface $request, array $options): void { $dnsQueries[] = $hostname . $type; // example.com SOA - if ($hostname === 'example.com') { + if ($hostname === 'example.com.') { return match ($type) { DNS_SOA => [ [ @@ -511,7 +511,7 @@ static function (RequestInterface $request, array $options): void { } // example.net A, AAAA, CNAME - if ($hostname === 'subsubdomain.subdomain.example.com') { + if ($hostname === 'subsubdomain.subdomain.example.com.') { return match ($type) { DNS_A => [ [ @@ -540,10 +540,10 @@ static function (RequestInterface $request, array $options): void { ); $this->assertCount(3, $dnsQueries); - $this->assertContains('example.com' . DNS_SOA, $dnsQueries); - $this->assertContains('subsubdomain.subdomain.example.com' . DNS_A, $dnsQueries); - $this->assertContains('subsubdomain.subdomain.example.com' . DNS_AAAA, $dnsQueries); + $this->assertContains('example.com.' . DNS_SOA, $dnsQueries); + $this->assertContains('subsubdomain.subdomain.example.com.' . DNS_A, $dnsQueries); + $this->assertContains('subsubdomain.subdomain.example.com.' . DNS_AAAA, $dnsQueries); // CNAME should not be queried if A or AAAA succeeded already - $this->assertNotContains('subsubdomain.subdomain.example.com' . DNS_CNAME, $dnsQueries); + $this->assertNotContains('subsubdomain.subdomain.example.com.' . DNS_CNAME, $dnsQueries); } }