IpAddressClassifier.php 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
  5. *
  6. * @author 2022 Christoph Wurst <christoph@winzerhof-wurst.at>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. namespace OC\Net;
  24. use IPLib\Address\IPv6;
  25. use IPLib\Factory;
  26. use IPLib\ParseStringFlag;
  27. use Symfony\Component\HttpFoundation\IpUtils;
  28. use function filter_var;
  29. /**
  30. * Classifier for IP addresses
  31. *
  32. * @internal
  33. */
  34. class IpAddressClassifier {
  35. private const LOCAL_ADDRESS_RANGES = [
  36. '100.64.0.0/10', // See RFC 6598
  37. '192.0.0.0/24', // See RFC 6890
  38. ];
  39. /**
  40. * Check host identifier for local IPv4 and IPv6 address ranges
  41. *
  42. * Hostnames are not considered local. Use the HostnameClassifier for those.
  43. *
  44. * @param string $ip
  45. *
  46. * @return bool
  47. */
  48. public function isLocalAddress(string $ip): bool {
  49. $parsedIp = Factory::parseAddressString(
  50. $ip,
  51. ParseStringFlag::IPV4_MAYBE_NON_DECIMAL | ParseStringFlag::IPV4ADDRESS_MAYBE_NON_QUAD_DOTTED
  52. );
  53. if ($parsedIp === null) {
  54. /* Not an IP */
  55. return false;
  56. }
  57. /* Replace by normalized form */
  58. if ($parsedIp instanceof IPv6) {
  59. $ip = (string)($parsedIp->toIPv4() ?? $parsedIp);
  60. } else {
  61. $ip = (string)$parsedIp;
  62. }
  63. if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
  64. /* Range address */
  65. return true;
  66. }
  67. if (IpUtils::checkIp($ip, self::LOCAL_ADDRESS_RANGES)) {
  68. /* Within local range */
  69. return true;
  70. }
  71. return false;
  72. }
  73. }