Mod GeoIP 1.2.7 now available for Apache 2.2.x & 2.4.x

Started by Gregg, April 22, 2012, 09:17:40 PM

Previous topic - Next topic

Gregg

mod_geoip 1.2.7 we have had available for Apache 2.4 here for a couple weeks and I finally got around to building it against Apache 2.2.22. This version has IPv6 support in the official source. The IPv6 support is still considered experimental, but official code instead of Sob's patch we had used for 1.2.5+IPv6 (Thanks Sob!). It uses the GeoLite Standard and IPv6 Country & City databases available at Maxmind.com. All of our versions of Apache now include IPv6 support so you may want to give this module a try.  You can get mod_geoip/1.2.7 from our download page.

DnvrSysEngr

Just installed and configured Mod_GeoIP and it has made my administration of my Apache 2.4.2 WEB Server so much easier when it comes to blocking out those in other countries/locales that want to try to hack my server.  The instructions are a bit vague and a little inaccurate on blocking, but once I figured it out, it works awesome.

mario

@DnvrSysEngr  you are welcome to report your experience and post better instructions

DnvrSysEngr

Mario:

Here is what happened when I installed and configured mod_geoip 1.2.7 on my Windows 2008 Server running Apache HTTPD Server 2.4.2 in a 32-bit environment.

When I followed the instructions in readme_first.html, the instructions stated to add the following to httpd.conf

<IfModule geoip_module>
   GeoIPEnable On
  # Specify full path to the database here!
  # Use only one database.
  # GeoIPDBFile /path/to/GeoIP.dat
  # GeoIPDBFile /path/to/GeoLiteCity.dat

  # IPv6 support use two databases
  GeoIPDBFile bin/GeoIPv6.dat
  GeoIPDBFile bin/GeoLiteCity.dat

</IfModule>

I did this with no problems (I even updated the GeoIPv6.dat and GeoLiteCity.dat files with no problems).


In the README file, there is a section for BLOCKING that states:

======== Blocking unwanted countries ==========

# This blocks traffic from China and Russia

GeoIPEnable On
GeoIPDBFile /path/to/GeoIP.dat

SetEnvIf GEOIP_COUNTRY_CODE CN BlockCountry
SetEnvIf GEOIP_COUNTRY_CODE RU BlockCountry

# ... place more countries here

Deny from env=BlockCountry

# Optional - use if you want to allow a specific IP address from the country you denied
# See http://httpd.apache.org/docs/1.3/mod/mod_access.html for more details
# Allow from 10.1.2.3

If you add the BlockCountry commands where it states to add them, which I was lead to believe was in the section of <IfModule geoip_module> and would make it look like:

<IfModule geoip_module>
   GeoIPEnable On
  # Specify full path to the database here!
  # Use only one database.
  # GeoIPDBFile /path/to/GeoIP.dat
  # GeoIPDBFile /path/to/GeoLiteCity.dat

  # IPv6 support use two databases
  GeoIPDBFile bin/GeoIPv6.dat
  GeoIPDBFile bin/GeoLiteCity.dat
SetEnvIf GEOIP_COUNTRY_CODE CN BlockCountry
SetEnvIf GEOIP_COUNTRY_CODE RU BlockCountry
Deny from env=BlockCountry


</IfModule>

I got the following error in my Application log of my event viewer:

The Apache service named  reported the following error:
>>> AH00526: Syntax error on line xxx of C:/Path/To/conf/httpd.conf:
The Apache service named  reported the following error:
>>> deny not allowed here 


Here is the section in my httpd.conf  I ended up placing the BlockCountry  statements instead of what the instructions for mod_geoip stated to make it work:

# AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None
    #
    # Controls who can get stuff from this server.
    #
    SetEnvIf GEOIP_COUNTRY_CODE CN BlockCountry
    SetEnvIf GEOIP_COUNTRY_CODE RU BlockCountry
    Deny from env=BlockCountry

    Require all granted
</Directory>

To make sure this was correct and  GEOIP was working correctly with the BlockCountry command, I added SetEnvIf GEO_COUNTRY_CODE US BlockCountry in as well and was then unable to access my website in Denver, Colorado from my ISP in Denver, Colorado.  As soon as I removed the statement I added, I was able to once again access my website. 

This is just a sampling of all the Country Codes I am using to block unwanted countries/locales.  I will say this works much better than blocking out blocks of IP addresses.

I am not as proficient as many others with Apache on this site, but this is how I got it work, and it works very well (Access logs and Mod_Security logs are much more manageable).  I used to have many "Deny from" IP address blocks where I am now using BlockCountry statements.

Any feedback on how to do this better would be much appreciated.

Gregg

Well, Deny and Allow (from 2.2.x) are not used in 2.4 without mod_access_compat (which I think is disabled by default)
I should rewrite those for 2.4 using the new style auth directives.

<RequireAll>
  Require all granted
  <RequireNone>
    Require env ENVVAR
  </RequireNone>
</RequireAll>


or possibly just;

  Require all granted
  Require not env ENVVAR




DnvrSysEngr

You are correct.  I am sill using 2.2 style directives.  I have not yet gotten around to updating my .conf files with 2.4 style directives.  I kept the 2.2 style directives and enable mod_access_compat as I was having issues with vhosts.  I remember you and I having a dialog about it when I first logged on here at ApacheHaus.

Thanks for the tips you just suggested. I will be trying them later this evening (if I ever get home from work).

DnvrSysEngr

Gregg:

I tried -
<RequireAll>
  Require all granted
  <RequireNone>
    Require env ENVVAR
  </RequireNone>
</RequireAll>

  Worked perfect

or possibly just;

  Require all granted
  Require not env ENVVA

  Did not work

Since I am now using 2.4 directives, instead of 2.2 (Deny,Allow), it forced me to clean up all the incorrect directives in httpd.conf and vhosts.conf.  Thanks for reminding me to go back and look at some of the errors/old directives in all of my .conf files.

Sob

I'm a little late, but I have one question... how much was IPv6 support tested? Because it seems to me that it's crashing my Apache (your 2.4.3, x64) with every request coming over IPv6.

Sob

I think I found it. First a simple test. You need mod_geoip with "GeoIPScanProxyHeaders On" and test script geoip.php (or any other means to show the variables):
<?php
  
foreach($_SERVER as $key=>$val) {
    if(
substr($key05)=='GEOIP') echo $key.': '.$val.PHP_EOL;
  }
?>


Then you can test any IP address using "telnet yourserver 80" and pasting the following (adjust path or Host if needed):
GET /geoip.php HTTP/1.1
Host: localhost
X-Forwarded-For: 2a02:38::1001

Request processing starts when all headers are received and those are ended by empty line, so remember to press Enter few times to be sure that server got it. Server should reply with headers and list of GEOIP* variables. With your module it works with all IPv4 addresses, but not with IPv6.

The problem is caused by GeoIP's implementation of inet_pton, which is used only on Windows. It does not return success and even if it did, the compared to native inet_pton (which is available on Vista+) it returns different results (it takes the wrong part of addrinfo structure). With this patch it works correctly:
diff -Naur GeoIP-1.4.8-gregg/libGeoIP/GeoIP.c GeoIP-1.4.8-gregg-fix/libGeoIP/GeoIP.c
--- GeoIP-1.4.8-gregg/libGeoIP/GeoIP.c 2012-11-20 18:55:29.965978600 +0100
+++ GeoIP-1.4.8-gregg-fix/libGeoIP/GeoIP.c 2012-11-20 19:09:07.102014500 +0100
@@ -257,6 +257,7 @@
static int _GeoIP_inet_pton(int af, const char *src, void *dst)
{
         struct addrinfo hints, *res, *ressave;
+        int found = 0;
 
         memset(&hints, 0, sizeof(struct addrinfo));
         hints.ai_family = af;
@@ -271,12 +272,20 @@
 
         while (res)
         {
-                memcpy(dst, res->ai_addr, res->ai_addrlen);
+                if(res->ai_family == AF_INET) {
+                        memcpy(dst, &((struct sockaddr_in *)res->ai_addr)->sin_addr, sizeof(struct in_addr));
+                        found = 1;
+                        break;
+                } else if(res->ai_family == AF_INET6) {
+                        memcpy(dst, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
+                        found = 1;
+                        break;
+                }
                 res = res->ai_next;
         }
 
         freeaddrinfo(ressave);
-        return 0;
+        return found;
}
#else
static int _GeoIP_inet_pton(int af, const char *src, void *dst) {

Gregg

Thanks Sob, I'll patch and build maybe this evening.

One thing it and prior versions have done, is crash on occasion when it's sent a local IP address. I wish the author would have it ignore those but no.