Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 38b5992

Browse filesBrowse files
feature #49726 [HttpFoundation] Add IpUtils::isPrivateIp (danielburger1337)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [HttpFoundation] Add IpUtils::isPrivateIp | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | N/A | License | MIT | Doc PR | symfony/symfony-docs#18102 This is only my second PR for this project, so I hope I followed all the guidelines correctly. Recently I had more and more use cases where I had to make exceptions (mostly rate limiting) for private IP ranges. Symfony currently does not provide an easy way to check if an IP is private or public but implements such logic internally (private constant) for the [NoPrivateNetworkHttpClient](https://github.com/symfony/symfony/blob/6.3/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php). This PR intents to make the private subnet list reusable by adding it to [IpUtils](https://github.com/symfony/symfony/blob/6.3/src/Symfony/Component/HttpFoundation/IpUtils.php). In the original PR of the NoPrivateNetworkHttpClient it was also briefly mentioned that this constant may have value when made public. #35566 (comment) I think symfony should and always should have exposed this constant. Commits ------- 6471582 [HttpFoundation] Add IpUtils::isPrivateIp
2 parents d5a4cb1 + 6471582 commit 38b5992
Copy full SHA for 38b5992

File tree

5 files changed

+59
-16
lines changed
Filter options

5 files changed

+59
-16
lines changed

‎src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php
+1-16Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,6 @@ final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwa
3030
{
3131
use HttpClientTrait;
3232

33-
private const PRIVATE_SUBNETS = [
34-
'127.0.0.0/8',
35-
'10.0.0.0/8',
36-
'192.168.0.0/16',
37-
'172.16.0.0/12',
38-
'169.254.0.0/16',
39-
'0.0.0.0/8',
40-
'240.0.0.0/4',
41-
'::1/128',
42-
'fc00::/7',
43-
'fe80::/10',
44-
'::ffff:0:0/96',
45-
'::/128',
46-
];
47-
4833
private HttpClientInterface $client;
4934
private string|array|null $subnets;
5035

@@ -74,7 +59,7 @@ public function request(string $method, string $url, array $options = []): Respo
7459

7560
$options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, &$lastPrimaryIp): void {
7661
if ($info['primary_ip'] !== $lastPrimaryIp) {
77-
if ($info['primary_ip'] && IpUtils::checkIp($info['primary_ip'], $subnets ?? self::PRIVATE_SUBNETS)) {
62+
if ($info['primary_ip'] && IpUtils::checkIp($info['primary_ip'], $subnets ?? IpUtils::PRIVATE_SUBNETS)) {
7863
throw new TransportException(sprintf('IP "%s" is blocked for "%s".', $info['primary_ip'], $info['url']));
7964
}
8065

‎src/Symfony/Component/HttpClient/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpClient/composer.json
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
"symfony/process": "^5.4|^6.0",
4343
"symfony/stopwatch": "^5.4|^6.0"
4444
},
45+
"conflict": {
46+
"symfony/http-foundation": "<6.3"
47+
},
4548
"autoload": {
4649
"psr-4": { "Symfony\\Component\\HttpClient\\": "" },
4750
"exclude-from-classmap": [

‎src/Symfony/Component/HttpFoundation/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* Create migration for session table when pdo handler is used
1111
* Add support for Relay PHP extension for Redis
1212
* The `Response::sendHeaders()` method now takes an optional HTTP status code as parameter, allowing to send informational responses such as Early Hints responses (103 status code)
13+
* Add `IpUtils::isPrivateIp`
1314
* Deprecate conversion of invalid values in `ParameterBag::getInt()` and `ParameterBag::getBoolean()`,
1415
* Deprecate ignoring invalid values when using `ParameterBag::filter()`, unless flag `FILTER_NULL_ON_FAILURE` is set
1516

‎src/Symfony/Component/HttpFoundation/IpUtils.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/IpUtils.php
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@
1818
*/
1919
class IpUtils
2020
{
21+
public const PRIVATE_SUBNETS = [
22+
'127.0.0.0/8', // RFC1700 (Loopback)
23+
'10.0.0.0/8', // RFC1918
24+
'192.168.0.0/16', // RFC1918
25+
'172.16.0.0/12', // RFC1918
26+
'169.254.0.0/16', // RFC3927
27+
'0.0.0.0/8', // RFC5735
28+
'240.0.0.0/4', // RFC1112
29+
'::1/128', // Loopback
30+
'fc00::/7', // Unique Local Address
31+
'fe80::/10', // Link Local Address
32+
'::ffff:0:0/96', // IPv4 translations
33+
'::/128', // Unspecified address
34+
];
35+
2136
private static array $checkedIps = [];
2237

2338
/**
@@ -191,4 +206,12 @@ public static function anonymize(string $ip): string
191206

192207
return $ip;
193208
}
209+
210+
/**
211+
* Checks if an IPv4 or IPv6 address is contained in the list of private IP subnets.
212+
*/
213+
public static function isPrivateIp(string $requestIp): bool
214+
{
215+
return self::checkIp($requestIp, self::PRIVATE_SUBNETS);
216+
}
194217
}

‎src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,35 @@ public static function getIp4SubnetMaskZeroData()
154154
[false, '1.2.3.4', '256.256.256/0'], // invalid CIDR notation
155155
];
156156
}
157+
158+
/**
159+
* @dataProvider getIsPrivateIpData
160+
*/
161+
public function testIsPrivateIp(string $ip, bool $matches)
162+
{
163+
$this->assertSame($matches, IpUtils::isPrivateIp($ip));
164+
}
165+
166+
public static function getIsPrivateIpData(): array
167+
{
168+
return [
169+
// private
170+
['127.0.0.1', true],
171+
['10.0.0.1', true],
172+
['192.168.0.1', true],
173+
['172.16.0.1', true],
174+
['169.254.0.1', true],
175+
['0.0.0.1', true],
176+
['240.0.0.1', true],
177+
['::1', true],
178+
['fc00::1', true],
179+
['fe80::1', true],
180+
['::ffff:0:1', true],
181+
['fd00::1', true],
182+
183+
// public
184+
['104.26.14.6', false],
185+
['2606:4700:20::681a:e06', false],
186+
];
187+
}
157188
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.