From aa45c07ebec5a11306d3fe2c7654745f5df02ed3 Mon Sep 17 00:00:00 2001 From: David Dreschner Date: Sat, 21 Mar 2026 19:32:53 +0100 Subject: [PATCH] fix(DnsPinning): Ensure to always lookup based on FQDN Signed-off-by: David Dreschner --- lib/private/Http/Client/DnsPinMiddleware.php | 8 ++++- .../lib/Http/Client/DnsPinMiddlewareTest.php | 36 +++++++++---------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/private/Http/Client/DnsPinMiddleware.php b/lib/private/Http/Client/DnsPinMiddleware.php index b031f3f32366f..f78bdb669176c 100644 --- a/lib/private/Http/Client/DnsPinMiddleware.php +++ b/lib/private/Http/Client/DnsPinMiddleware.php @@ -34,7 +34,9 @@ private function soaRecord(string $target): ?array { $top = count($labels) >= 2 ? array_pop($labels) : ''; $second = array_pop($labels); - $hostname = $second . '.' . $top; + // Before looking up any DNS record, we need to make sure the + // provided target is an FQDN by adding a dot to the end. + $hostname = $second . '.' . $top . '.'; $responses = $this->dnsGetRecord($hostname, DNS_SOA); if ($responses === false || count($responses) === 0) { @@ -59,6 +61,10 @@ private function dnsResolve(string $target, int $recursionCount) : array { $dnsTypes = \defined('AF_INET6') || @inet_pton('::1') ? [DNS_A, DNS_AAAA, DNS_CNAME] : [DNS_A, DNS_CNAME]; + + // Before looking up any DNS record, we need to make sure the + // provided target is an FQDN by adding a dot to the end. + $target = str_ends_with($target, '.') ? $target : "$target."; foreach ($dnsTypes as $dnsType) { if ($canHaveCnameRecord === false && $dnsType === DNS_CNAME) { continue; 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); } }