فهرست منبع

Fix local DNS leak when fetching feeds through a proxy (#9451)

* Fix local DNS leak when fetching feeds through a proxy

Follow-up to #9390: `getRetryAfterFile()` passed the full URL to
`Minz_Request::serverIsPublic()`, which then resolved the target hostname
with the local resolver (`dns_get_record()`), even when a proxy was
configured. With a socks5h/socks4a proxy this leaks the target hostname
to the local DNS and defeats remote name resolution.

- `Minz_Request::serverIsPublic()`: add an `$allowDnsResolve` parameter,
  and forward it to the recursive call so the guard holds for the whole
  recursion.
- `FreshRSS_http_Util::getRetryAfterFile()`: do not resolve the host name
  when a proxy is configured (`$proxy === ''`), since the proxy is
  responsible for DNS.

---------

Co-authored-by: Inverle <inverle@proton.me>
tomac4t 1 روز پیش
والد
کامیت
859a2ad039
3فایلهای تغییر یافته به همراه5 افزوده شده و 5 حذف شده
  1. 1 1
      app/Utils/httpUtil.php
  2. 3 3
      lib/Minz/Request.php
  3. 1 1
      lib/composer.json

+ 1 - 1
app/Utils/httpUtil.php

@@ -32,7 +32,7 @@ final class FreshRSS_http_Util {
 			return '';
 			return '';
 		}
 		}
 		// Once per host, as serverIsPublic() may resolve it
 		// Once per host, as serverIsPublic() may resolve it
-		$domainWide = self::$retry_after_domain_wide[$domain] ??= Minz_Request::serverIsPublic($url);
+		$domainWide = self::$retry_after_domain_wide[$domain] ??= Minz_Request::serverIsPublic($url, allowDnsResolve: $proxy === '');
 		$port = parse_url($url, PHP_URL_PORT);
 		$port = parse_url($url, PHP_URL_PORT);
 		if (is_int($port)) {
 		if (is_int($port)) {
 			$domain .= ':' . $port;
 			$domain .= ':' . $port;

+ 3 - 3
lib/Minz/Request.php

@@ -430,7 +430,7 @@ class Minz_Request {
 	 * @param string $address the address to test, which can be an URL with a DNS or an IP.
 	 * @param string $address the address to test, which can be an URL with a DNS or an IP.
 	 * @return bool true if server does not appear to be on some kind of local network, false otherwise (probably public).
 	 * @return bool true if server does not appear to be on some kind of local network, false otherwise (probably public).
 	 */
 	 */
-	public static function serverIsPublic(string $address): bool {
+	public static function serverIsPublic(string $address, bool $allowDnsResolve = true): bool {
 		if (strlen($address) < strlen('http://a.bc')) {
 		if (strlen($address) < strlen('http://a.bc')) {
 			return false;
 			return false;
 		}
 		}
@@ -445,12 +445,12 @@ class Minz_Request {
 			&& !preg_match('/^(\\[)?(::1|f[c-d][0-9a-f]{2}:|fe80:)(\\])?/i', $host);	// IPv6
 			&& !preg_match('/^(\\[)?(::1|f[c-d][0-9a-f]{2}:|fe80:)(\\])?/i', $host);	// IPv6
 
 
 		// If $host looks public and is not an IP address, try to resolve it
 		// If $host looks public and is not an IP address, try to resolve it
-		if ($is_public && filter_var($host, FILTER_VALIDATE_IP) === false) {
+		if ($allowDnsResolve && $is_public && filter_var($host, FILTER_VALIDATE_IP) === false) {
 			$resolvedIp = self::resolveHostname($host);
 			$resolvedIp = self::resolveHostname($host);
 			if ($resolvedIp !== null && $resolvedIp !== $host) {
 			if ($resolvedIp !== null && $resolvedIp !== $host) {
 				$resolvedAddress = str_contains($resolvedIp, ':') ? "http://[{$resolvedIp}]/" : "http://{$resolvedIp}/";
 				$resolvedAddress = str_contains($resolvedIp, ':') ? "http://[{$resolvedIp}]/" : "http://{$resolvedIp}/";
 				if ($resolvedAddress !== $address) {
 				if ($resolvedAddress !== $address) {
-					$is_public &= self::serverIsPublic($resolvedAddress);
+					$is_public &= self::serverIsPublic($resolvedAddress, $allowDnsResolve);
 				}
 				}
 			}
 			}
 		}
 		}

+ 1 - 1
lib/composer.json

@@ -18,7 +18,7 @@
 		"marienfressinaud/lib_opml": "dev-main#f0e850b6394af90b898daf0e65fcc7363457b844",
 		"marienfressinaud/lib_opml": "dev-main#f0e850b6394af90b898daf0e65fcc7363457b844",
 		"phpgt/cssxpath": "v1.6.0",
 		"phpgt/cssxpath": "v1.6.0",
 		"phpmailer/phpmailer": "7.1.1",
 		"phpmailer/phpmailer": "7.1.1",
-		"simplepie/simplepie": "dev-freshrss#fcfbf7769eb9b3725a1f07b609771b0d7a12b0c7"
+		"simplepie/simplepie": "dev-freshrss#042298d6550e74225cf0eedba1913cf68976d6bb"
 	},
 	},
 	"config": {
 	"config": {
 		"sort-packages": true,
 		"sort-packages": true,