| Current Path : /home/juvelize/martine/plugins/system/cwgears/helpers/ |
| Current File : /home/juvelize/martine/plugins/system/cwgears/helpers/iptools.php |
<?php
/**
* @package Joomla
* @subpackage CoalaWeb Gears
* @author Steven Palmer <support@coalaweb.com>
* @link https://coalaweb.com/
* @license GNU/GPL V3 or later; https://www.gnu.org/licenses/gpl-3.0.html
* @copyright Copyright (c) 2021 Steven Palmer All rights reserved.
*
* CoalaWeb Gears is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 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 General Public License for more details.
*/
defined('_JEXEC') or die('Restricted access');
/**
* Class CwGearsIptools
*/
class CwGearsIptools {
/**
* Get users IP address
*
* @return string
*/
public static function getUserIP() {
$ip = self::_real_getUserIP();
if ((strstr($ip, ',') !== false) || (strstr($ip, ' ') !== false)) {
$ip = str_replace(' ', ',', $ip);
$ip = str_replace(',,', ',', $ip);
$ips = explode(',', $ip);
$ip = '';
while (empty($ip) && !empty($ips)) {
$ip = array_pop($ips);
$ip = trim($ip);
}
} else {
$ip = trim($ip);
}
return $ip;
}
/**
* Gets the visitor's IP address
*
* @return string
*/
private static function _real_getUserIP() {
// Normally the $_SERVER superglobal is set
if (isset($_SERVER)) {
$ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');
foreach ($ip_keys as $key) {
if (array_key_exists($key, $_SERVER) === true) {
foreach (explode(',', $_SERVER[$key]) as $ip) {
// trim for safety measures
$ip = trim($ip);
// attempt to validate IP
if (self::validate_ip($ip)) {
return $ip;
}
}
}
}
return self::validate_ip($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
}
// This part is executed on PHP running as CGI, or on SAPIs which do
// not set the $_SERVER superglobal
// If getenv() is disabled, you're screwed
if (function_exists('getenv')) {
$ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');
foreach ($ip_keys as $key) {
if (getenv($key)) {
foreach (explode(',', getenv($key)) as $ip) {
// trim for safety measures
$ip = trim($ip);
// attempt to validate IP
if (self::validate_ip($ip)) {
return $ip;
}
}
}
}
return self::validate_ip(getenv('REMOTE_ADDR')) ? getenv('REMOTE_ADDR') : '';
}
// Catch-all case for broken servers, apparently
return '';
}
/**
* Ensures an ip address is both a valid IP and does not fall within
* a private network range.
*/
protected static function validate_ip($ip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
return false;
}
return true;
}
/**
* Is this an IPv6 IP address?
*
* @param string $ip An IPv4 or IPv6 address
*
* @return boolean True if it's IPv6
*/
public static function isIPv6($ip) {
if (strstr($ip, ':')) {
return true;
}
return false;
}
/**
* Converts inet_pton output to bits string
*
* @param string $inet The in_addr representation of an IPv4 or IPv6 address
*
* @return string
*/
protected static function inet_to_bits($inet) {
if (strlen($inet) == 4) {
$unpacked = unpack('A4', $inet);
} else {
$unpacked = unpack('A16', $inet);
}
$unpacked = str_split($unpacked[1]);
$binaryip = '';
foreach ($unpacked as $char) {
$binaryip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
}
return $binaryip;
}
/**
* Checks if an IP is contained in a list of IPs or IP expressions
*
* @param string $ip The IPv4/IPv6 address to check
* @param array $ipTable The list of IP expressions
*
* @return null|boolean True if it's in the list, null if the filtering can't proceed
*/
public static function ipinList($ip, $ipTable = array()) {
// No point proceeding with an empty IP list
if (empty($ipTable)) {
return null;
}
// If no IP address is found, return null (unsupported)
if ($ip == '0.0.0.0') {
return null;
}
// If no IP is given, return null (unsupported)
if (empty($ip)) {
return null;
}
// Sanity check
if (!function_exists('inet_pton')) {
return null;
}
// Get the IP's in_adds representation
$myIP = @inet_pton($ip);
// If the IP is in an unrecognisable format, quite
if ($myIP === false) {
return null;
}
$ipv6 = self::isIPv6($ip);
foreach ($ipTable as $ipExpression) {
$ipExpression = trim($ipExpression);
// Inclusive IP range, i.e. 123.123.123.123-124.125.126.127
if (strstr($ipExpression, '-')) {
list($from, $to) = explode('-', $ipExpression, 2);
if ($ipv6 && (!self::isIPv6($from) || !self::isIPv6($to))) {
// Do not apply IPv4 filtering on an IPv6 address
continue;
} elseif (!$ipv6 && (self::isIPv6($from) || self::isIPv6($to))) {
// Do not apply IPv6 filtering on an IPv4 address
continue;
}
$from = @inet_pton(trim($from));
$to = @inet_pton(trim($to));
// Sanity check
if (($from === false) || ($to === false)) {
continue;
}
// Swap from/to if they're in the wrong order
if ($from > $to) {
list($from, $to) = array($to, $from);
}
if (($myIP >= $from) && ($myIP <= $to)) {
return true;
}
}
// Netmask or CIDR provided
elseif (strstr($ipExpression, '/')) {
$binaryip = self::inet_to_bits($myIP);
list($net, $maskbits) = explode('/', $ipExpression, 2);
if ($ipv6 && !self::isIPv6($net)) {
// Do not apply IPv4 filtering on an IPv6 address
continue;
} elseif (!$ipv6 && self::isIPv6($net)) {
// Do not apply IPv6 filtering on an IPv4 address
continue;
} elseif (!$ipv6 && strstr($maskbits, '.')) {
// Convert IPv4 netmask to CIDR
$long = ip2long($maskbits);
$base = ip2long('255.255.255.255');
$maskbits = 32 - log(($long ^ $base) + 1, 2);
}
// Convert network IP to in_addr representation
$net = @inet_pton($net);
// Sanity check
if ($net === false) {
continue;
}
// Get the network's binary representation
$binarynet = self::inet_to_bits($net);
// Check the corresponding bits of the IP and the network
$ip_net_bits = substr($binaryip, 0, $maskbits);
$net_bits = substr($binarynet, 0, $maskbits);
if ($ip_net_bits == $net_bits) {
return true;
}
} else {
// IPv6: Only single IPs are supported
if ($ipv6) {
$ipExpression = trim($ipExpression);
if (!self::isIPv6($ipExpression)) {
continue;
}
$ipCheck = @inet_pton($ipExpression);
if ($ipCheck === false) {
continue;
}
if ($ipCheck == $myIP) {
return true;
}
} else {
// Standard IPv4 address, i.e. 123.123.123.123 or partial IP address, i.e. 123.[123.][123.][123]
$dots = 0;
if (substr($ipExpression, -1) == '.') {
// Partial IP address. Convert to CIDR and re-match
foreach (count_chars($ipExpression, 1) as $i => $val) {
if ($i == 46) {
$dots = $val;
}
}
switch ($dots) {
case 1:
$netmask = '255.0.0.0';
$ipExpression .= '0.0.0';
break;
case 2:
$netmask = '255.255.0.0';
$ipExpression .= '0.0';
break;
case 3:
$netmask = '255.255.255.0';
$ipExpression .= '0';
break;
default:
$dots = 0;
}
if ($dots) {
$binaryip = self::inet_to_bits($myIP);
// Convert netmask to CIDR
$long = ip2long($netmask);
$base = ip2long('255.255.255.255');
$maskbits = 32 - log(($long ^ $base) + 1, 2);
$net = @inet_pton($ipExpression);
// Sanity check
if ($net === false) {
continue;
}
// Get the network's binary representation
$binarynet = self::inet_to_bits($net);
// Check the corresponding bits of the IP and the network
$ip_net_bits = substr($binaryip, 0, $maskbits);
$net_bits = substr($binarynet, 0, $maskbits);
if ($ip_net_bits == $net_bits) {
return true;
}
}
}
if (!$dots) {
$ip = @inet_pton(trim($ipExpression));
if ($ip == $myIP) {
return true;
}
}
}
}
}
return false;
}
/**
* Checks if an IP is contained in a list of IPs or IP expressions
*
* @param string $ip The IPv4/IPv6 address to check
* @param array $ipTable The list of IP expressions
*
* @return null|boolean True if it's in the list, null if the filtering can't proceed
*/
public static function titleinList($ip, $ipTable = array()) {
// No point proceeding with an empty IP list
if (empty($ipTable)) {
return null;
}
// If no IP address is found, return null (unsupported)
if ($ip == '0.0.0.0') {
return null;
}
// If no IP is given, return null (unsupported)
if (empty($ip)) {
return null;
}
// Sanity check
if (!function_exists('inet_pton')) {
return null;
}
// Get the IP's in_adds representation
$myIP = @inet_pton($ip);
// If the IP is in an unrecognisable format, quite
if ($myIP === false) {
return null;
}
$ipv6 = self::isIPv6($ip);
foreach ($ipTable as $i => $ipExpression) {
$ipExpression2 = trim($ipExpression['0']);
$foo = '';
// Inclusive IP range, i.e. 123.123.123.123-124.125.126.127
if (strstr($ipExpression2, '-')) {
list($from, $to) = explode('-', $ipExpression2, 2);
if ($ipv6 && (!self::isIPv6($from) || !self::isIPv6($to))) {
// Do not apply IPv4 filtering on an IPv6 address
continue;
} elseif (!$ipv6 && (self::isIPv6($from) || self::isIPv6($to))) {
// Do not apply IPv6 filtering on an IPv4 address
continue;
}
$from = @inet_pton(trim($from));
$to = @inet_pton(trim($to));
// Sanity check
if (($from === false) || ($to === false)) {
continue;
}
// Swap from/to if they're in the wrong order
if ($from > $to) {
list($from, $to) = array($to, $from);
}
if (($myIP >= $from) && ($myIP <= $to)) {
$foo = $ipExpression['1'];
return $foo;
}
}
// Netmask or CIDR provided
elseif (strstr($ipExpression2, '/')) {
$binaryip = self::inet_to_bits($myIP);
list($net, $maskbits) = explode('/', $ipExpression2, 2);
if ($ipv6 && !self::isIPv6($net)) {
// Do not apply IPv4 filtering on an IPv6 address
continue;
} elseif (!$ipv6 && self::isIPv6($net)) {
// Do not apply IPv6 filtering on an IPv4 address
continue;
} elseif (!$ipv6 && strstr($maskbits, '.')) {
// Convert IPv4 netmask to CIDR
$long = ip2long($maskbits);
$base = ip2long('255.255.255.255');
$maskbits = 32 - log(($long ^ $base) + 1, 2);
}
// Convert network IP to in_addr representation
$net = @inet_pton($net);
// Sanity check
if ($net === false) {
continue;
}
// Get the network's binary representation
$binarynet = self::inet_to_bits($net);
// Check the corresponding bits of the IP and the network
$ip_net_bits = substr($binaryip, 0, $maskbits);
$net_bits = substr($binarynet, 0, $maskbits);
if ($ip_net_bits == $net_bits) {
$foo = $ipExpression['1'];
return $foo;
}
} else {
// IPv6: Only single IPs are supported
if ($ipv6) {
$ipExpression2 = trim($ipExpression2);
if (!self::isIPv6($ipExpression2)) {
continue;
}
$ipCheck = @inet_pton($ipExpression2);
if ($ipCheck === false) {
continue;
}
if ($ipCheck == $myIP) {
$foo = $ipExpression['1'];
return $foo;
}
} else {
// Standard IPv4 address, i.e. 123.123.123.123 or partial IP address, i.e. 123.[123.][123.][123]
$dots = 0;
if (substr($ipExpression2, -1) == '.') {
// Partial IP address. Convert to CIDR and re-match
foreach (count_chars($ipExpression2, 1) as $i => $val) {
if ($i == 46) {
$dots = $val;
}
}
switch ($dots) {
case 1:
$netmask = '255.0.0.0';
$ipExpression2 .= '0.0.0';
break;
case 2:
$netmask = '255.255.0.0';
$ipExpression2 .= '0.0';
break;
case 3:
$netmask = '255.255.255.0';
$ipExpression2 .= '0';
break;
default:
$dots = 0;
}
if ($dots) {
$binaryip = self::inet_to_bits($myIP);
// Convert netmask to CIDR
$long = ip2long($netmask);
$base = ip2long('255.255.255.255');
$maskbits = 32 - log(($long ^ $base) + 1, 2);
$net = @inet_pton($ipExpression2);
// Sanity check
if ($net === false) {
continue;
}
// Get the network's binary representation
$binarynet = self::inet_to_bits($net);
// Check the corresponding bits of the IP and the network
$ip_net_bits = substr($binaryip, 0, $maskbits);
$net_bits = substr($binarynet, 0, $maskbits);
if ($ip_net_bits == $net_bits) {
$foo = $ipExpression['1'];
return $foo;
}
}
}
if (!$dots) {
$ip = @inet_pton(trim($ipExpression2));
if ($ip == $myIP) {
$foo = $ipExpression['1'];
return $foo;
}
}
}
}
}
return $foo;
}
}