From 74910eddb6047a0ce31a49e9151a6c4cbc4a9b17 Mon Sep 17 00:00:00 2001 From: flashwave Date: Mon, 24 Dec 2018 19:58:12 +0100 Subject: [PATCH] Added CIDR IP range checking function, closes #88. --- public/index.php | 29 ---------------- src/Net/ip.php | 90 +++++++++++++++++++++--------------------------- utility.php | 11 ------ 3 files changed, 39 insertions(+), 91 deletions(-) diff --git a/public/index.php b/public/index.php index e6bbc42a..071f9430 100644 --- a/public/index.php +++ b/public/index.php @@ -19,35 +19,6 @@ if (MSZ_DEBUG) { } return; } - - if (!empty($_GET['cidr'])) { - header('Content-Type: text/plain'); - - $checks = [ - [ - 'cidr' => '104.16.0.0/12', - 'addrs' => [ - '104.28.8.4', - '104.28.9.4', - '94.211.73.13', - ], - ], - ]; - - foreach ($checks as $check) { - $mask = ip_cidr_to_mask($check['cidr']); - - echo 'MASK> ' . inet_ntop($mask) . "\t" . decbin_str($mask) . PHP_EOL; - - foreach ($check['addrs'] as $addr) { - $addr = inet_pton($addr); - echo 'ADDR> ' . inet_ntop($addr) . "\t" . decbin_str($addr) . "\t" . ip_match_mask($addr, $mask) . PHP_EOL; - } - - echo PHP_EOL; - } - return; - } } if (config_get_default(false, 'Site', 'embed_linked_data')) { diff --git a/src/Net/ip.php b/src/Net/ip.php index bccc2f44..02616169 100644 --- a/src/Net/ip.php +++ b/src/Net/ip.php @@ -13,17 +13,17 @@ function ip_remote_address(string $fallback = '::1'): string return $_SERVER['REMOTE_ADDR'] ?? $fallback; } -function ip_country_code(string $ipAddr, string $fallback = 'XX'): string +function ip_country_code(string $address, string $fallback = 'XX'): string { try { - return geoip_country($ipAddr)->country->isoCode ?? $fallback; + return geoip_country($address)->country->isoCode ?? $fallback; } catch (Exception $e) { } return $fallback; } -function ip_detect_string_version(string $address): int +function ip_get_string_version(string $address): int { if (filter_var($address, FILTER_VALIDATE_IP) === false) { return MSZ_IP_UNKNOWN; @@ -40,13 +40,13 @@ function ip_detect_string_version(string $address): int return MSZ_IP_UNKNOWN; } -function ip_detect_raw_version(string $raw, bool $returnWidth = false): int +function ip_get_raw_version(string $raw): int { $rawLength = strlen($raw); foreach (MSZ_IP_SIZES as $version => $length) { if ($rawLength === $length) { - return $returnWidth ? $length : $version; + return $version; } } @@ -58,54 +58,42 @@ function ip_get_raw_width(int $version): int return MSZ_IP_SIZES[$version] ?? 0; } -// Takes 1.2.3.4/n notation, returns subnet mask in raw bytes -function ip_cidr_to_mask(string $ipRange): string +function ip_match_cidr_raw(string $address, string $subnet, int $mask = 0): bool { - [$address, $bits] = explode('/', $ipRange, 2); + $version = ip_get_raw_version($subnet); + $bits = ip_get_raw_width($version) * 8; + + if (empty($mask)) { + $mask = $bits; + } + + if ($mask < 1 || $mask > $bits || $version !== ip_get_raw_version($subnet)) { + return false; + } + + for ($i = 0; $i < ceil($mask / 8); $i++) { + $byteMask = (0xFF00 >> min(8, $mask - ($i * 8))) & 0xFF; + $addressByte = ord($address[$i]) & $byteMask; + $subnetByte = ord($subnet[$i]) & $byteMask; + + if ($addressByte !== $subnetByte) { + return false; + } + } + + return true; +} + +function ip_match_cidr(string $address, string $cidr): bool +{ + if (strpos($cidr, '/') !== false) { + [$subnet, $mask] = explode('/', $cidr, 2); + } else { + $subnet = $cidr; + } $address = inet_pton($address); - $width = ip_detect_raw_version($address, true) * 8; + $subnet = inet_pton($subnet); - if ($bits < 1 || $bits > $width) { - return str_repeat(chr(0), $width); - } - - $mask = ''; - - for ($i = 0; $i < floor($width / 8); $i++) { - $addressByte = ord($address[$i]); - $maskByte = 0; - - for ($j = 0; $j < 8; $j++) { - $offset = (8 * $i) + $j; - $bit = 0x80 >> $j; - - if ($offset < $bits && ($addressByte & $bit) > 0) { - $maskByte |= $bit; - } else { - $maskByte &= ~$bit; - } - } - - $mask .= chr($maskByte); - } - - return $mask; -} - -// Takes a RAW IP and a RAW MASK -function ip_match_mask(string $ipAddress, string $mask): int -{ - $width = strlen($mask); - $result = false; - - if (strlen($ipAddress) !== $width) { - return $result; - } - - for ($i = 0; $i < $width; $i++) { - $result &= ($ipAddress[$i] & ~$mask[$i]) === 0; - } - - return $result; + return ip_match_cidr_raw($address, $subnet, $mask ?? 0); } diff --git a/utility.php b/utility.php index 841b39b0..caf29b6d 100644 --- a/utility.php +++ b/utility.php @@ -342,14 +342,3 @@ function is_user_int($value): bool { return ctype_digit(strval($value)); } - -function decbin_str(string $str): string -{ - $out = ''; - - for ($i = 0; $i < strlen($str); $i++) { - $out .= str_pad(decbin(ord($str[$i])), 8, '0'); - } - - return $out; -}