-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Implementing trusted_proxies CIDR notation capability for IPv6 #12535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 21 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
4dd4379
Adding IpAddress handling utility classes in OC\Net namespace
olivermg 5efc12f
Working on IpAddress classes for CIDR
olivermg 54c3694
Merge branch 'master' of github.com:nextcloud/server into feature/655…
olivermg 9c98e43
Adding test for IpAddressFactory
olivermg fc7b744
adding tests to IpAddressV4Test.php
olivermg 9674d3b
Merge branch 'master' of github.com:nextcloud/server into feature/655…
olivermg 7b9f5bc
adding tests for IpAddressV4
olivermg 587025a
renaming tests
olivermg 8d35b0e
adding tests for IpAddressV6
olivermg 5fa3396
adding tests for localhost
olivermg af610cd
moving common methods from IPAddressV[46] to AbstractIpAddress
olivermg a5503ad
adding author to Request.php
olivermg cf554e0
removing empty setUp & tearDown methods from tests
olivermg 0920691
shrinking IIpAddress interface to sensible minimum
olivermg b26e862
Merge branch 'master' of github.com:nextcloud/server into feature/655…
olivermg b4a5d8f
remove matchesTrustedProxy function from Request.php
olivermg 02c6ed1
adding license headers to new source files
olivermg ad76224
updating config.sample.php to reflect IPv6 CIDR notation
olivermg 361871d
adding function header comments
olivermg efc02c6
adding license file headers to test files
olivermg 29488ec
Merge branch 'master' of github.com:nextcloud/server into feature/655…
olivermg caf3df2
updating license statements in files of OC\Net
olivermg 4ad17fc
pushing @since in \OC\Net\IIpAddress to 16.0.0
olivermg 9b66b4f
moving IIpAddress and IpAddressFactory to OCP namespace
olivermg 36aec3f
adding @author lines
olivermg 811befa
removing obsolete members from concrete IpAddressV[46] classes
olivermg f82f4fb
introduce IIpAddressFactory and move IpAddressFactory to OC namespace
olivermg 733b416
Merge branch 'master' of github.com:olivermg/server into feature/6550…
olivermg 638d876
Merge branch 'master' of github.com:nextcloud/server into feature/655…
olivermg bc413ea
inject IIpAddressFactory into Request
olivermg a8f7ea4
check if an IIpAddressFactory exists in Request
olivermg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ | |
| * @author Lukas Reschke <[email protected]> | ||
| * @author Mitar <[email protected]> | ||
| * @author Morris Jobke <[email protected]> | ||
| * @author Oliver Wegner <[email protected]> | ||
| * @author Robin Appelman <[email protected]> | ||
| * @author Robin McCorkell <[email protected]> | ||
| * @author Roeland Jago Douma <[email protected]> | ||
|
|
@@ -41,6 +42,8 @@ | |
| use OC\Security\CSRF\CsrfToken; | ||
| use OC\Security\CSRF\CsrfTokenManager; | ||
| use OC\Security\TrustedDomainHelper; | ||
| use OC\Net\IIpAddress; | ||
| use OC\Net\IpAddressFactory; | ||
| use OCP\IConfig; | ||
| use OCP\IRequest; | ||
| use OCP\Security\ICrypto; | ||
|
|
@@ -598,37 +601,19 @@ public function getId(): string { | |
| return $this->requestId; | ||
| } | ||
|
|
||
| /** | ||
| * Checks if given $remoteAddress matches given $trustedProxy. | ||
| * If $trustedProxy is an IPv4 IP range given in CIDR notation, true will be returned if | ||
| * $remoteAddress is an IPv4 address within that IP range. | ||
| * Otherwise $remoteAddress will be compared to $trustedProxy literally and the result | ||
| * will be returned. | ||
| * @return boolean true if $remoteAddress matches $trustedProxy, false otherwise | ||
| */ | ||
| protected function matchesTrustedProxy($trustedProxy, $remoteAddress) { | ||
| $cidrre = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/([0-9]{1,2})$/'; | ||
|
|
||
| if (preg_match($cidrre, $trustedProxy, $match)) { | ||
| $net = $match[1]; | ||
| $shiftbits = min(32, max(0, 32 - intval($match[2]))); | ||
| $netnum = ip2long($net) >> $shiftbits; | ||
| $ipnum = ip2long($remoteAddress) >> $shiftbits; | ||
|
|
||
| return $ipnum === $netnum; | ||
| } | ||
|
|
||
| return $trustedProxy === $remoteAddress; | ||
| } | ||
|
|
||
| /** | ||
| * Checks if given $remoteAddress matches any entry in the given array $trustedProxies. | ||
| * For details regarding what "match" means, refer to `matchesTrustedProxy`. | ||
| * 'Matching' here means | ||
| * - $remoteAddress is either equal to an entry in $trustedProxies or | ||
| * - $remoteAddress is an IP address in the range of any IP ranges specified in $trustedProxies | ||
| * @return boolean true if $remoteAddress matches any entry in $trustedProxies, false otherwise | ||
| */ | ||
| protected function isTrustedProxy($trustedProxies, $remoteAddress) { | ||
| $ipAddressRemote = IpAddressFactory::new($remoteAddress); | ||
|
|
||
| foreach ($trustedProxies as $tp) { | ||
| if ($this->matchesTrustedProxy($tp, $remoteAddress)) { | ||
| $ipAddressProxy = IpAddressFactory::new($tp); | ||
| if ($ipAddressProxy->containsAddress($ipAddressRemote)) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| /** | ||
| * @copyright Copyright (c) 2018, ownCloud, Inc. | ||
| * | ||
| * @author Oliver Wegner <[email protected]> | ||
| * | ||
| * @license AGPL-3.0 | ||
| * | ||
| * This code is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License, version 3, | ||
| * as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU Affero General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Affero General Public License, version 3, | ||
| * along with this program. If not, see <http://www.gnu.org/licenses/> | ||
| * | ||
| */ | ||
|
|
||
| namespace OC\Net; | ||
|
|
||
| use OC\Net\IIpAddress; | ||
|
|
||
| abstract class AbstractIpAddress implements IIpAddress { | ||
| abstract public function getMaxBitlength(): int; | ||
| abstract protected function getCidrRegex(): string; | ||
| abstract protected function matchCidr(IIpAddress $other): bool; | ||
|
|
||
| private $original = ''; | ||
| private $netPart = ''; | ||
| private $netmaskBits = 0; | ||
|
|
||
| /** | ||
| * Constructor that takes an IP address in string form and | ||
| * initializes this instance to represent that address | ||
| * | ||
| * @param string $address | ||
| */ | ||
| public function __construct(string $address) { | ||
| $this->setOriginal($address); | ||
|
|
||
| if (preg_match($this->getCidrRegex(), $address, $match)) { | ||
| $this->setNetPart($match[1]); | ||
| $this->setNetmaskBits(max(0, min($this->getMaxBitlength(), intval($match[2])))); | ||
| } else { | ||
| $this->setNetPart($address); | ||
| $this->setNetmaskbits($this->getMaxBitlength()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Sets the literal address string that this instance | ||
| * represents | ||
| * | ||
| * @param string $original | ||
| */ | ||
| protected function setOriginal(string $original) { | ||
| $this->original = $original; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the literal address string that this instance | ||
| * represents | ||
| * | ||
| * @return string | ||
| */ | ||
| protected function getOriginal(): string { | ||
| return $this->original; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the network part of the | ||
| * address/range represented by this instance | ||
| * | ||
| * @param string $netPart | ||
| */ | ||
| protected function setNetPart(string $netPart) { | ||
| $this->netPart = $netPart; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the network part of the | ||
| * address/range represented by this instance | ||
| * | ||
| * @return string | ||
| */ | ||
| protected function getNetPart(): string { | ||
| return $this->netPart; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the number of bits of the net part of the IP | ||
| * address/range represented by this instance | ||
| * | ||
| * @param int $bits | ||
| */ | ||
| protected function setNetmaskBits(int $bits) { | ||
| $this->netmaskBits = $bits; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the number of bits of the net part of the IP | ||
| * address/range represented by this instance | ||
| * | ||
| * @return int | ||
| */ | ||
| protected function getNetmaskBits(): int { | ||
| return $this->netmaskBits; | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether $other is literally equivalent to this instance | ||
| * | ||
| * @return bool | ||
| */ | ||
| protected function matchOriginal(IIpAddress $other): bool { | ||
| return $other->getOriginal() === $this->getOriginal(); | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether this instance represents an IP range (vs. | ||
| * a single IP address) | ||
| * | ||
| * @return bool | ||
| */ | ||
| public function isRange(): bool { | ||
| return $this->getNetmaskBits() < $this->getMaxBitlength(); | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether given $other address is either | ||
| * - equal to this instance regarding its IP address or | ||
| * - is contained in the IP address range represented by this instance | ||
| * | ||
| * @param IIpAddress $other | ||
| * @return bool | ||
| */ | ||
| public function containsAddress(IIpAddress $other): bool { | ||
| return $this->isRange() | ||
| ? $this->matchCidr($other) | ||
| : $this->matchOriginal($other); | ||
| } | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| /** | ||
| * @copyright Copyright (c) 2018, ownCloud, Inc. | ||
| * | ||
| * @author Oliver Wegner <[email protected]> | ||
| * | ||
| * @license AGPL-3.0 | ||
| * | ||
| * This code is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License, version 3, | ||
| * as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU Affero General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Affero General Public License, version 3, | ||
| * along with this program. If not, see <http://www.gnu.org/licenses/> | ||
| * | ||
| */ | ||
|
|
||
| /** | ||
| * Private interface of ownCloud for internal use. | ||
| * IpAddress interface | ||
| */ | ||
|
|
||
| /** | ||
| * This interface provides functionalities of an IP address or range, | ||
| * e.g. checking if an IP address is within an IP range. | ||
| * | ||
| * @since 15.0.0 | ||
MorrisJobke marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| */ | ||
|
|
||
| namespace OC\Net; | ||
|
|
||
| interface IIpAddress { | ||
|
|
||
| /** | ||
| * Returns whether this instance represents an IP range. | ||
| * | ||
| * @return boolean true if this is an IP range, false if it's a single IP address | ||
| * @since 15.0.0 | ||
| */ | ||
| public function isRange(): bool; | ||
|
|
||
| /** | ||
| * Returns if $other is equal to or contained in the IP | ||
| * address(es) which this instance represents. | ||
| * | ||
| * @return boolean true if $other is part of (or equal to) $this in terms of | ||
| * IP range terms, false otherwise | ||
| * @since 15.0.0 | ||
| */ | ||
| public function containsAddress(IIpAddress $other): bool; | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| <?php | ||
| declare(strict_types=1); | ||
| /** | ||
| * @copyright Copyright (c) 2018, ownCloud, Inc. | ||
| * | ||
| * @author Oliver Wegner <[email protected]> | ||
| * | ||
| * @license AGPL-3.0 | ||
| * | ||
| * This code is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU Affero General Public License, version 3, | ||
| * as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU Affero General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Affero General Public License, version 3, | ||
| * along with this program. If not, see <http://www.gnu.org/licenses/> | ||
| * | ||
| */ | ||
|
|
||
| namespace OC\Net; | ||
|
|
||
| use OC\Net\IIpAddress; | ||
| use OC\Net\IpAddressV4; | ||
| use OC\Net\IpAddressV6; | ||
|
|
||
| class IpAddressFactory { | ||
| /** | ||
| * Returns whether $address represents an IPv6 address | ||
| * | ||
| * @param string $address | ||
| * @return bool | ||
| */ | ||
| public static function isIpv6(string $address): bool { | ||
| return strpos($address, ':') !== false; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a new instance conforming to IIpAddress and | ||
| * representing the given $address. | ||
| * | ||
| * @param string $address | ||
| * @return IIpAddress | ||
| */ | ||
| public static function new($address): IIpAddress { | ||
| if (self::isIpv6($address)) { | ||
| return new IpAddressV6($address); | ||
| } else { | ||
| return new IpAddressV4($address); | ||
| } | ||
| } | ||
| } | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.