Many thanks for the v2.7.2. Now, it gets the correct IP. But only if the order in HTTP_X_FORWARDED_FOR is unchanged.
So, I dived into the code and would like to make a suggestion. I made a little private function to determine the real client IP. I’ve tried to make this process more reliable to get the real IP under different circumstances. I hope the inline-comments are understandable.
I guess, it is not perfect, but maybe an improvement. What do you think?
Here comes the function to get the real client IP:
private function getRealRemoteIp() {
$return_ip = null;
// reverse proxy environments
if (cerber_get_options('proxy') && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$list = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($list as $maybe_ip) {
$return_ip = filter_var(trim($maybe_ip), FILTER_VALIDATE_IP);
// in reverse proxy environment REMOTE_ADDR has the proxy IP
// in IP is different to REMOTE_ADDR this should be the client IP
// In case that there is only one IP in HTTP_X_FORWARDED_FOR this
// could be the server IP anyways.
if ($return_ip && $return_ip != $_SERVER['REMOTE_ADDR']) break;
}
// HTTP_X_REAL_IP should only be set behind proxy.
// Some servers fills its own IP, so we have to check this.
if (isset($_SERVER['HTTP_X_REAL_IP']) &&
$_SERVER['HTTP_X_REAL_IP'] != $_SERVER['REMOTE_ADDR'] &&
$_SERVER['HTTP_X_REAL_IP'] != $return_ip) {
$tmp = filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP);
// only overwrite the already set variable if we have a valid IP from HTTP_X_REAL_IP
$return_ip = ($tmp) ? $tmp : $return_ip;
}
// non-proxy environment
} else {
if (isset($_SERVER['REMOTE_ADDR'])) $return_ip = $_SERVER['REMOTE_ADDR'];
elseif (isset($_SERVER['HTTP_CLIENT_IP'])) $return_ip = $_SERVER['HTTP_CLIENT_IP'];
elseif (isset($_SERVER['SERVER_ADDR'])) $return_ip = $_SERVER['SERVER_ADDR'];
$return_ip = filter_var($return_ip, FILTER_VALIDATE_IP);
}
// No IP address was found? Roll back to localhost.
if (!$return_ip) $return_ip = '127.0.0.1';
return $return_ip;
}
Now, the __construct
could be shrinked like this:
function __construct() {
$this->remote_ip = $this->getRealRemoteIp();
$this->status = 0; // Default: OK!
if (cerber_is_citadel()) $this->status = 3;
elseif (!cerber_is_allowed($this->remote_ip)) {
if (cerber_acl_check($this->remote_ip,'B')) $this->status = 1;
else $this->status = 2;
}
}