IpAddressClassifier.php 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Net;
  8. use IPLib\Address\IPv6;
  9. use IPLib\Factory;
  10. use IPLib\ParseStringFlag;
  11. use Symfony\Component\HttpFoundation\IpUtils;
  12. use function filter_var;
  13. /**
  14. * Classifier for IP addresses
  15. *
  16. * @internal
  17. */
  18. class IpAddressClassifier {
  19. private const LOCAL_ADDRESS_RANGES = [
  20. '100.64.0.0/10', // See RFC 6598
  21. '192.0.0.0/24', // See RFC 6890
  22. ];
  23. /**
  24. * Check host identifier for local IPv4 and IPv6 address ranges
  25. *
  26. * Hostnames are not considered local. Use the HostnameClassifier for those.
  27. */
  28. public function isLocalAddress(string $ip): bool {
  29. $parsedIp = Factory::parseAddressString(
  30. $ip,
  31. ParseStringFlag::IPV4_MAYBE_NON_DECIMAL | ParseStringFlag::IPV4ADDRESS_MAYBE_NON_QUAD_DOTTED | ParseStringFlag::MAY_INCLUDE_ZONEID
  32. );
  33. if ($parsedIp === null) {
  34. /* Not an IP */
  35. return false;
  36. }
  37. /* Replace by normalized form */
  38. if ($parsedIp instanceof IPv6) {
  39. $ip = (string)($parsedIp->toIPv4() ?? $parsedIp);
  40. } else {
  41. $ip = (string)$parsedIp;
  42. }
  43. if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
  44. /* Range address */
  45. return true;
  46. }
  47. if (IpUtils::checkIp($ip, self::LOCAL_ADDRESS_RANGES)) {
  48. /* Within local range */
  49. return true;
  50. }
  51. return false;
  52. }
  53. }