Game server and admin dashboard for TerranQuest.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IPUtils.lib.php 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <?php
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. class IPUtils {
  6. /**
  7. * Check if a given ipv4 address is in a given cidr
  8. * @param string $ip IP to check in IPV4 format eg. 127.0.0.1
  9. * @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
  10. * @return boolean true if the ip is in this range / false if not.
  11. * @author Thorsten Ott <https://gist.github.com/tott/7684443>
  12. */
  13. public static function ip4_in_cidr($ip, $cidr) {
  14. if (strpos($cidr, '/') == false) {
  15. $cidr .= '/32';
  16. }
  17. // $range is in IP/CIDR format eg 127.0.0.1/24
  18. list( $cidr, $netmask ) = explode('/', $cidr, 2);
  19. $range_decimal = ip2long($cidr);
  20. $ip_decimal = ip2long($ip);
  21. $wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
  22. $netmask_decimal = ~ $wildcard_decimal;
  23. return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
  24. }
  25. /**
  26. * Check if a given ipv6 address is in a given cidr
  27. * @param string $ip IP to check in IPV6 format
  28. * @param string $cidr CIDR netmask
  29. * @return boolean true if the IP is in this range, false otherwise.
  30. * @author MW. <https://stackoverflow.com/a/7952169>
  31. */
  32. public static function ip6_in_cidr($ip, $cidr) {
  33. $address = inet_pton($ip);
  34. $subnetAddress = inet_pton(explode("/", $cidr)[0]);
  35. $subnetMask = explode("/", $cidr)[1];
  36. $addr = str_repeat("f", $subnetMask / 4);
  37. switch ($subnetMask % 4) {
  38. case 0:
  39. break;
  40. case 1:
  41. $addr .= "8";
  42. break;
  43. case 2:
  44. $addr .= "c";
  45. break;
  46. case 3:
  47. $addr .= "e";
  48. break;
  49. }
  50. $addr = str_pad($addr, 32, '0');
  51. $addr = pack("H*", $addr);
  52. $binMask = $addr;
  53. return ($address & $binMask) == $subnetAddress;
  54. }
  55. /**
  56. * Check if the REMOTE_ADDR is on Cloudflare's network.
  57. * @return boolean true if it is, otherwise false
  58. */
  59. public static function validateCloudflare() {
  60. if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
  61. // Using IPv6
  62. $cloudflare_ips_v6 = [
  63. "2400:cb00::/32",
  64. "2405:8100::/32",
  65. "2405:b500::/32",
  66. "2606:4700::/32",
  67. "2803:f800::/32",
  68. "2c0f:f248::/32",
  69. "2a06:98c0::/29"
  70. ];
  71. $valid = false;
  72. foreach ($cloudflare_ips_v6 as $cidr) {
  73. if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
  74. $valid = true;
  75. break;
  76. }
  77. }
  78. } else {
  79. // Using IPv4
  80. $cloudflare_ips_v4 = [
  81. "103.21.244.0/22",
  82. "103.22.200.0/22",
  83. "103.31.4.0/22",
  84. "104.16.0.0/12",
  85. "108.162.192.0/18",
  86. "131.0.72.0/22",
  87. "141.101.64.0/18",
  88. "162.158.0.0/15",
  89. "172.64.0.0/13",
  90. "173.245.48.0/20",
  91. "188.114.96.0/20",
  92. "190.93.240.0/20",
  93. "197.234.240.0/22",
  94. "198.41.128.0/17"
  95. ];
  96. $valid = false;
  97. foreach ($cloudflare_ips_v4 as $cidr) {
  98. if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
  99. $valid = true;
  100. break;
  101. }
  102. }
  103. }
  104. return $valid;
  105. }
  106. /**
  107. * Makes a good guess at the client's real IP address.
  108. *
  109. * @return string Client IP or `0.0.0.0` if we can't find anything
  110. */
  111. public static function getClientIP() {
  112. // If CloudFlare is in the mix, we should use it.
  113. // Check if the request is actually from CloudFlare before trusting it.
  114. if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
  115. if (validateCloudflare()) {
  116. return $_SERVER["HTTP_CF_CONNECTING_IP"];
  117. }
  118. }
  119. if (isset($_SERVER["REMOTE_ADDR"])) {
  120. return $_SERVER["REMOTE_ADDR"];
  121. }
  122. return "0.0.0.0"; // This will not happen unless we aren't a web server
  123. }
  124. }