How can I get the user's IP while using both CloudFlare and MaxMind's GeoIP with mod_geoip?

CloudFlare provides the user's country from the originating IP but I need location on a city level so I've added MaxMind's GeoCityLite using the mod_geoip Apache script.

The problem is now to get the IP in a php variable, I'm using something like

$country = apache_note("GEOIP_COUNTRY_CODE");

This is great but the IP mod_geoip is using is the CloudFlare DNS, not the end user. CloudFlare offers the server variable HTTP_CF_CONNECTING_IP to use the end-user IP but how do I use THAT variable/IP in the mod_geoip?

Can this be done with a few lines in htaccess?

Edit: I have a workaround using the php API for geoip which is easy but the benchmarks using the apache lookup of the php api is much much better so I'd rather find this solution.

Answers


do this before you call geoip:

$_SERVER['REMOTE_ADDR'] = isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : $_SERVER['REMOTE_ADDR'];

I was having difficulty trying to get both the Larvel TrustedProxy work with both CloudFlare and AWS' EC2 Elastic Load Balancer together. It assumes you only use 1 proxy, not 2 and doesn't work right. I ended up just skipping the trusted proxy stuff all together and making a simple MiddleWare that if using CloudFlare, regardless if you have another Load Balancer in front of it, it'll just set the right IP address and protocol.

CloudFlare passes information about the client through HTTP headers: https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-CloudFlare-handle-HTTP-Request-headers-

We're taking both the client IP and the client HTTP/HTTPS protocol and setting that into the $request->server attributes.

======

app/Http/Middleware/UseCloudFlareHeaders.php

<?php namespace App\Http\Middleware;

use Closure;

class UseCloudFlareHeaders
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        //if CloudFlare request, set correct protocol and proper client ip address
        $HTTP_CF_VISITOR = $request->server->get('HTTP_CF_VISITOR');
        $HTTP_CF_CONNECTING_IP = $request->server->get('HTTP_CF_CONNECTING_IP');

        if ($HTTP_CF_VISITOR and json_decode($HTTP_CF_VISITOR)->scheme == 'https') {
            $request->server->set('HTTPS', 'on');
        }

        if ($HTTP_CF_CONNECTING_IP) {
            $request->server->set('REMOTE_ADDR', $HTTP_CF_CONNECTING_IP);
        }

        return $next($request);
    }
}

app/Http/Kernal.php

protected $middleware = [
    //add this to your middleware...
    \App\Http\Middleware\UseCloudFlareHeaders::class
];

If someone knows a better way of doing this, please let us know.


Cloudflare has an Apache extension mod_cloudflare (https://github.com/cloudflare/CloudFlare-Tools) which I believe replaces the Cloudflare IP with the correct one.

If it's loaded before mod_geoip it might work depending on how mod_geoip works.

You will need root access to install mod_cloudflare though.


To get a user's IP address stored in a variable like $ip, you can do it in a couple ways:

$ip = $_SERVER['REMOTE_ADDR'];

or

$ip = getenv('REMOTE_ADDR');

Need Your Help

Should I unit test the methods or commands on a view model?

.net wpf mvvm viewmodel view-model-pattern

I just finished watching Jason Dolinger's video on MVVM, and I'd like some clarification on how to properly setup and unit test the ICommand properties of my view models.

Truncating an md5 hash, How do I calculate the odds of a collision occurring?

md5

I want to truncate an md5 hash to about half size. How much does that increase the odds of collisions? if I'm dealing with around 500 000 generations, should I be worried about a collision? what ab...