isTrustedProxy($remoteAddr)) { // Check headers in order of trust preference $headers = [ 'HTTP_CF_CONNECTING_IP', // Cloudflare 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', ]; foreach ($headers as $header) { if (!empty($_SERVER[$header])) { $ips = explode(',', $_SERVER[$header]); $ip = trim($ips[0]); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { return $ip; } } } } // Validate and return direct connection IP if (filter_var($remoteAddr, FILTER_VALIDATE_IP)) { return $remoteAddr; } return '0.0.0.0'; } /** * Check if the given IP is a trusted proxy * * @param string $ip The IP address to check * @return bool Whether the IP is a trusted proxy */ protected function isTrustedProxy(string $ip): bool { // Check if trusted proxies are configured if (!defined('WC_LICENSE_TRUSTED_PROXIES')) { return false; } $trustedProxies = WC_LICENSE_TRUSTED_PROXIES; // Handle string constant (comma-separated list) if (is_string($trustedProxies)) { $trustedProxies = array_map('trim', explode(',', $trustedProxies)); } if (!is_array($trustedProxies)) { return false; } // Check for special keywords if (in_array('CLOUDFLARE', $trustedProxies, true)) { if ($this->isCloudflareIp($ip)) { return true; } } // Check direct IP match or CIDR notation foreach ($trustedProxies as $proxy) { if ($proxy === $ip) { return true; } // Support CIDR notation if (str_contains($proxy, '/') && $this->ipMatchesCidr($ip, $proxy)) { return true; } } return false; } /** * Check if IP is in Cloudflare range * * @param string $ip The IP to check * @return bool Whether IP belongs to Cloudflare */ protected function isCloudflareIp(string $ip): bool { // Cloudflare IPv4 ranges (as of 2024) $cloudflareRanges = [ '173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/13', '104.24.0.0/14', '172.64.0.0/13', '131.0.72.0/22', ]; foreach ($cloudflareRanges as $range) { if ($this->ipMatchesCidr($ip, $range)) { return true; } } return false; } /** * Check if an IP matches a CIDR range * * @param string $ip The IP to check * @param string $cidr The CIDR range (e.g., "192.168.1.0/24") * @return bool Whether the IP matches the CIDR range */ protected function ipMatchesCidr(string $ip, string $cidr): bool { [$subnet, $bits] = explode('/', $cidr); if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) || !filter_var($subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return false; } $ipLong = ip2long($ip); $subnetLong = ip2long($subnet); $mask = -1 << (32 - (int) $bits); return ($ipLong & $mask) === ($subnetLong & $mask); } }