Skip to content

Commit ce59add

Browse files
Better handles reserved IPv6 addresses in WebFetchApi::isFetchSafe()
1 parent 87ab825 commit ce59add

3 files changed

Lines changed: 12 additions & 10 deletions

File tree

Sources/IP.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,15 @@ public function __construct(self|string|null $ip)
100100
}
101101
// Is it in a valid IPv6 string?
102102
elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
103-
// Pack and unpack to ensure it is in standard form.
104-
$this->ip = inet_ntop(inet_pton($ip));
103+
if (str_starts_with($ip, '64:ff9b::')) {
104+
// Workaround for a PHP bug where NAT64 addresses aren't handled
105+
// properly when the last 32 bits are in IPv6 notation instead
106+
// of IPv4 notation. See https://en.wikipedia.org/wiki/NAT64.
107+
$this->ip = '64:ff9b::' . inet_ntop(hex2bin(substr(bin2hex(inet_pton($ip)), -8)));
108+
} else {
109+
// Pack and unpack to ensure it is in standard form.
110+
$this->ip = inet_ntop(inet_pton($ip));
111+
}
105112
}
106113
// It's either in binary form or it's invalid.
107114
else {

Sources/Url.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ public function proxied(): self
499499
// Don't proxy URLs whose hosts are private or reserved IP addresses.
500500
|| (
501501
filter_var($proxied->host, FILTER_VALIDATE_IP) !== false
502-
&& filter_var($proxied->host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false
502+
&& filter_var($proxied->host, FILTER_VALIDATE_IP, FILTER_FLAG_GLOBAL_RANGE) === false
503503
)
504504
) {
505505
return $proxied;

Sources/WebFetch/WebFetchApi.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
use SMF\Lang;
1919
use SMF\Url;
20+
use SMF\IP;
2021

2122
/**
2223
* Class SearchApi
@@ -256,13 +257,7 @@ public static function isFetchSafe(Url $url, array $allowed_schemes = []): bool
256257
// Couldn't resolve to anything: refuse rather than guess.
257258
$ips === []
258259
// EVERY resolved address must be a global, public, unicast IP.
259-
|| $ips !== filter_var_array(
260-
$ips,
261-
[
262-
'filter' => FILTER_VALIDATE_IP,
263-
'flags' => FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE,
264-
],
265-
)
260+
|| $ips !== array_filter($ips, fn($ip) => IP::create($ip)->isValid(FILTER_FLAG_GLOBAL_RANGE)),
266261
) {
267262
self::$safe_hosts[$url->host] = false;
268263
}

0 commit comments

Comments
 (0)