pax_global_header00006660000000000000000000000064124763634440014527gustar00rootroot0000000000000052 comment=c2f7fbc7d4fca963f7301bd16497947e3b8bbb4b geoip-api-mod_geoip2-1.2.10/000077500000000000000000000000001247636344400155045ustar00rootroot00000000000000geoip-api-mod_geoip2-1.2.10/.uncrustify.cfg000066400000000000000000000064101247636344400204570ustar00rootroot00000000000000# # based on uncrustify config file for the linux kernel # code_width = 80 indent_case_brace = 4 indent_columns = 4 indent_label = 2 # pos: absolute col, neg: relative column indent_with_tabs = 0 # # inter-symbol newlines # nl_brace_else = remove # "} else" vs "} \n else" - cuddle else nl_brace_while = remove # "} while" vs "} \n while" - cuddle while nl_do_brace = remove # "do {" vs "do \n {" nl_else_brace = remove # "else {" vs "else \n {" nl_enum_brace = remove # "enum {" vs "enum \n {" nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{" nl_fdef_brace = force # "int foo() {" vs "int foo()\n{" nl_for_brace = remove # "for () {" vs "for () \n {" nl_func_var_def_blk = 0 # don't add newlines after a block of var declarations nl_if_brace = remove # "if () {" vs "if () \n {" nl_multi_line_define = true nl_struct_brace = remove # "struct {" vs "struct \n {" nl_switch_brace = remove # "switch () {" vs "switch () \n {" nl_union_brace = remove # "union {" vs "union \n {" nl_while_brace = remove # "while () {" vs "while () \n {" # # Source code modifications # mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();" mod_full_brace_for = force # "for () a--;" vs "for () { a--; }" mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }" mod_full_brace_nl = 3 # don't remove if more than 3 newlines mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }" mod_paren_on_return = remove # "return 1;" vs "return (1);" # # inter-character spacing options # sp_after_cast = remove # "(int) a" vs "(int)a" sp_after_comma = force sp_after_sparen = force # "if () {" vs "if (){" sp_arith = force sp_assign = force sp_assign = force sp_before_comma = remove sp_before_ptr_star = force # "char *foo" vs "char* foo sp_before_sparen = force # "if (" vs "if(" sp_between_ptr_star = remove # "char * *foo" vs "char **foo" sp_bool = force sp_compare = force sp_func_call_paren = remove # "foo (" vs "foo(" sp_func_def_paren = remove # "int foo (){" vs "int foo(){" sp_func_proto_paren = remove # "int foo ();" vs "int foo();" sp_inside_braces = force # "{ 1 }" vs "{1}" sp_inside_braces_enum = force # "{ 1 }" vs "{1}" sp_inside_braces_struct = force # "{ 1 }" vs "{1}" sp_inside_sparen = remove sp_paren_brace = force sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)" # # Aligning stuff # align_enum_equ_span = 4 # '=' in enum definition align_nl_cont = true align_on_tabstop = FALSE # align on tabstops align_right_cmt_span = 3 align_struct_init_span = 1 align_struct_init_span = 3 # align stuff in a structure init '= { }' align_var_def_star_style = 2 # void *foo; align_var_struct_span = 0 align_with_tabs = FALSE # use tabs to align geoip-api-mod_geoip2-1.2.10/Changes000066400000000000000000000120411247636344400167750ustar00rootroot000000000000001.2.10 2015-03-06 - Update docs to note that GeoIP configuration directives cannot be placed in .htaccess files. - Fix small memleak (Boris Zentner) - A segfault when using multi-threaded workers was fixed. (Fix from thinker0. GitHub #16.) - Several instances of manual memory management were switched to use the use Apache's memory pool. (Fix from thinker0. GitHub #16.) 1.2.9 2014-03-20 - Added a new directive, GeoIPScanProxyHeaderField, to specify a custom header which contains the client's IP address (Sascha Kuehndel) - Added the ability to forward the result fields to a backend server/proxy via request header (Sascha Kuehndel) 1.2.9 2013-01-08 - Add GeoIPUseFirstNonPrivateXForwardedForIP option (Boris Zentner) - Support Apache 2.4 (Boris Zentner) - Use GeoIP_id_by_addr_v6 instead of GeoIP_country_id_by_addr_v6 (Boris Zentner) - Include util_script.h to silence warning about ap_add_common_vars (Boris Zentner) 1.2.7 2011-08-23 - Add support for GEOIP_NETSPEED_REV1 (Boris Zentner) - Experimental support for GEOIP_COUNTRY_EDITION_V6 (Boris Zentner) - Add GEOIP_DOMAIN_EDITION support (Boris Zentner) 1.2.6 2008-09-11 - GEOIP_METRO_CODE replace the depreciated GEOIP_DMA_CODE (Boris Zentner) 1.2.5 2008-08-13 ! Fix GEOIP_REGION and GEOIP_COUNTRY_CODE when used with the GeoIPRegion database. Both are only set if a region or country was found. Previously a empty string was assigned to both (Boris Zentner) - Add GEOIP_REGION_NAME for City and Region databases (Boris Zentner) 1.2.4 2008-06-10 ! mod_geoip2 has sets GEOIP_COUNTRY_CODE to -- for unknown countries when used with the country database. But for any other database (City for example) GEOIP_COUNTRY_CODE is unset for unknown countries. This is fixed now. Same for GEOIP_CONTINENT_CODE and GEOIP_COUNTRY_NAME. (Boris Zentner) - Add GEOIP_ADDR. That's the address used to compute the geoip information. Exported as env, notes or both as usual (Jason Caldwell) - Try to run always before mod_setenvif and mod_rewrite. (Boris Zentner) 1.2.3 2008-04-26 - Skip files that we can not open for some reason (permission/typo). Check and skip empty slots in geoip_header_parser (Boris Zentner) - Slight performance increase - don't make per_dir ap_get_module_config call where we return DECLINED because cfg->GeoIPEnabled is true (Guenter Knauf) - NetWare/Win32 compilation fixes, since can't declare vars in middle of code (Guenter Knauf) 1.2.2 2008-03-18 - Fix race condition for IO based caches like Standard. MMapCache and MemoryCache are not affected. (Boris Zentner) 1.2.1 2007-12-17 ! Notice - all directives are _only_ valid in server context except GeoIPEnabled. Check you configuration with apachectl configtest (Boris Zentner) - Added MMapCache option (Boris Zentner) - Change GeoIPEnabled from a serverwide option to a server/directory/location keyword. (Boris Zentner) - Fix a small memleak per child. Allocated in geoip_child_init free in geoip_cleanup (Boris Zentner) - GeoIP databases get used serverwide now. Not per child. See the README. (Boris Zentner) - Update README with more examples (Boris Zentner) - Added support for UTF8 output for GeoIP City databases (Boris Zentner) 1.2.0 2007-08-30 - Fix segfault issue if GeoIP.dat file cannot be opened (Vladimir Sedlacek) - Added support for GEOIP_CONTINENT_CODE for GeoIP Country and City (Frank Mather) - Added GeoIPScanProxyHeaders directive to handle X-Forwarded-For headers (Frank Mather) - Updated documentation to specify that GeoIPFlags need to be passed as second parameter to GeoIPDBFile, instead of using the GeoIPFlags directive 1.1.8 2006-04-28 - Updated README file with GeoIPFlags docs and performance tips - Added apr_strings.h include (Dann Frazier, Fixes Debian #357387) - Added support for IndexCache 1.1.7 2005-08-01 - Copied docs in mod_geoip1.3 in README on how to redirect and block by country - Fixed Garbage characters appearing in GeoIP Postal Code field, this bug was introduced in 1.1.3 1.1.6 2005-05-17 - Fixed empty fields for GeoIP Region fields, this bug was introduced in 1.1.3 1.1.5 2005-04-19 - Removed dependence on DNS resolver for GeoIP Region and Netspeed databases 1.1.4 2004-12-23 - Fixed Garbage characters appearing in GeoIP City/Region field, this bug was introduced in 1.1.3 1.1.3 2004-12-09 - Added support for GeoIPOutput - Changed command setup to AP_INIT_TAKE12 from AP_INIT_TAKE1 GeoIPDBFile (merv) - Memory Leak fix when using GeoIP Region database - Memory Leak fix when using GeoIP City database (Shane Nelson) 1.1.2 2004-08-12 - Added support for GeoIP Netspeed Edition (Frank Mather) - Added support for GeoIP City setting GEOIP_DMA_CODE, GEOIP_AREA_CODE, GEOIP_LATITUDE, GEOIP_LONGITUDE, and GEOIP_POSTAL_CODE (Frank Mather) 1.1.1 2004-07-12 - Added more documentation for using from PHP - Fixed compile errors and warnings 1.1.0 2004-04-19 - Added support for GeoIP Region, City, ISP and Organization (Frank Mather) 1.0.6 2002-08-30 - Added GeoIP_delete upon cleanup (Corris Randall) 1.0.5 2002-08-29 - Initial Release (Corris Randall) geoip-api-mod_geoip2-1.2.10/INSTALL.md000066400000000000000000000033701247636344400171370ustar00rootroot00000000000000# Installation ## Requirements Apache 2.0.40 or higher installed If using RPM, the httpd-devel package containing apxs may need to be installed [GeoIP 1.4.8 or higher installed](https://github.com/maxmind/geoip-api-c/releases). ## Building To build mod_geoip as a dynamically loadable module: ``` apxs -i -a -L/usr/local/lib -I/usr/local/include -lGeoIP -c mod_geoip.c ``` `-I/usr/local/include` is where the GeoIP.h header file is installed. `-L/usr/local/lib` is where the libGeoIP library is located. This will put the correct LoadModule statement. ## Configuration To enable the module, place ``` GeoIPEnable On ``` inside your httpd.conf file. The `` block is not required but is recommended. You can optionally specify the data file by using: ``` GeoIPEnable On GeoIPDBFile /usr/tmp/GeoIP.dat ``` See the README.md file for more details on the configuration ## Troubleshooting On RedHat 9, apxs places ``` LoadModule geoip_module /usr/lib/httpd/modules/mod_geoip.so ``` Inside a ``` ``` Block. If mod_geoip2 doesn't work, try taking the LoadModule geoip_module line outside the `` block. If you get the following errors: ``` parse error before "geoip_module" warning: data definition has no type or storage class ``` Or ``` syntax error before "geoip_module" ``` Make sure that the apxs script belongs to the Apache server you are using. These error messages result from using a Apache 1.3 apxs script with a Apache 2.x server. If you get a `libGeoIP.so.1: cannot open shared object file: No such file or directory` error, add `/usr/local/lib` to `/etc/ld.so.conf` then run `/sbin/ldconfig /etc/ld.so.conf` geoip-api-mod_geoip2-1.2.10/LICENSE000066400000000000000000000045201247636344400165120ustar00rootroot00000000000000/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2004 MaxMind, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== */ geoip-api-mod_geoip2-1.2.10/README.md000066400000000000000000000431041247636344400167650ustar00rootroot00000000000000GeoIP Legacy Apache Module ========================== Important Note -------------- This API is for the GeoIP Legacy format (dat). To read the MaxMind DB format (mmdb) used by GeoIP2, please see [mod_maxminddb](https://github.com/maxmind/mod_maxminddb) Description ----------- The mod_geoip2 module embeds GeoIP Legacy database lookups into the Apache web server. It is only capable of looking up the IP of a client that connects to the web server, as opposed to looking up arbitrary addresses. This module works with Apache 2. Please use [mod_geoip](http://www.maxmind.com/download/geoip/api/mod_geoip/mod_geoip-latest.tar.gz) with Apache 1. Installation ------------ You can [download mod_geoip2](https://github.com/maxmind/geoip-api-mod_geoip2/releases) from GitHub or get the latest development version from [GitHub](https://github.com/maxmind/geoip-api-mod_geoip2). See the `INSTALL` file in the tarball for installation details. Overview -------- The mod_geoip2 module uses the libGeoIP library to look up geolocation information for a client as part of the http request process. This module is free software, and is licensed under the [Apache license](http://www.apache.org/licenses/LICENSE-2.0.html). To compile and install this module, you must first install [libGeoIP 1.4.3](/?page_id=44#MaxMind-Supported_APIs) or newer. The mod_geoip2 module takes effect either during request header parsing phase or the post read request phase, depending on whether it is configured for server-wide use or for a specific location/directory. When enabled, the module looks at the incoming IP address and sets some variables which provide geolocation information for that IP. The variables it set depend on the specific GeoIP Legacy database being used (Country, City, ISP, etc.). These variables can be set in either the request notes table, the environment or both depending on the server configuration. Configuration ------------- With the exception of `GeoIPEnable`, all GeoIP configuration directives must be placed in the server-wide context of the main server config. (Please see [Server vs Directory context](#Server_vs_Directory_context) for a full explanation). After installing the module, make sure that GeoIPEnable On is set in your Apache configuration file or an `.htaccess` file. This will call the GeoIP Legacy Country database from its default location (e.g. /usr/local/share/GeoIP/GeoIP.dat) If you want to specify options, for example to use a different database or to pass caching options, you can use the `GeoIPDBFile` directive: ### File and Caching Directives GeoIPDBFile /path/to/GeoIP.dat [GeoIPFlag] For example: GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache GeoIPDBFile /usr/local/share/GeoIP/GeoIPOrg.dat Standard The default GeoIPFlag value is Standard, which does not perform any caching, but uses the least memory. To turn on memory caching use: GeoIPDBFile /path/to/GeoIP.dat MemoryCache The memory cache option can use a large amount of memory. We recommend that you use Memory Caching only for the smaller database files, such as GeoIP Legacy Country and GeoIP Legacy ISP. Another MemoryCache option is MMapCache, which uses the the `mmap` system call to map the database file into memory. If you would like the API to check to see if your local GeoIP Legacy files have been updated, set the `CheckCache` flag: GeoIPDBFile /path/to/GeoIP.dat CheckCache Before making a call to the database, geoip will check the GeoIP.dat file to see if it has changed. If it has, then it will reload the file. With this option, you do not have to restart Apache when you update your GeoIP Legacy databases. If you would like to turn on partial memory caching, use the `IndexCache` flag: GeoIPDBFile /path/to/GeoIP.dat IndexCache The IndexCache option caches the most frequently accessed index portion of the database, resulting in faster lookups than StandardCache, but less memory usage than MemoryCache. This is especially useful for larger databases such as GeoIP Legacy Organization and GeoIP Legacy City. For the GeoIP Legacy Country, Region and Netspeed databases, setting the IndexCache option just causes the C API to use the MemoryCache. Currently, multiple GeoIPFlags options can not be combined. ### Enabling UTF-8 Output You may change the output charset from ISO-8859-1 (Latin-1) to UTF-8 with this directive: GeoIPEnableUTF8 On By default mod_geoip2 sets variables in both the notes table and environment. For performance reasons you may want to set only the one you use. To do so, use the `GeoIPOutput` configuration directive: ### Output Variable Location GeoIPOutput Notes # Sets the Apache notes table only GeoIPOutput Env # Sets environment variables only GeoIPOutput Request # Sets input headers with the geo location information GeoIPOutput All # Sets all three (default behaviour) ### Proxy-Related Directives By default, this module will simply look at the IP address of the client. However, if the client is using a proxy, this will be the address of the proxy. You can use the `GeoIPScanProxyHeaders` directive to look at proxy-related headers. GeoIPScanProxyHeaders On When this is set, the module will look at several other sources for the IP address, in this order: - The `HTTP_CLIENT_IP` environment variable (set by Apache). - The `HTTP_X_FORWARDED_FOR` environment variable (set by Apache). - The `X-Forwarded-For` for header (set by a proxy). - The `HTTP_REMOTE_ADDR` environment variable (set by Apache). This module will use the first IP address it finds in one of these locations *instead* of the IP address the client connected from. Some of these variables may contain a comma-separate list of IP addresses (when a client goes through multiple proxies). In this case, the default behavior is to use the first IP address. You can set the `GeoIPUseLastXForwardedForIP` directive to use the last address instead: GeoIPUseLastXForwardedForIP On Or use `GeoIPUseFirstNonPrivateXForwardedForIP` to use the first non private IP Address. GeoIPUseFirstNonPrivateXForwardedForIP On Apache 2.4 users using mod_remoteip to pick the IP address of the user should disable GeoIPScanProxyHeaders. Mod_geoip2 will use whatever mod_remoteip provides. GeoIPScanProxyHeaderField FieldName Sometimes it is useful to use another field as the source for the client's IP address. You can set this directive to tell this module which header to look at in order to determine the client's IP address. Output Variables ---------------- As noted above, these variables can be set in either the Apache request notes table, the environment, or both. The specific variables which are set depend on the database you are using. ### GeoIP Country Edition Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_CONTINENT_CODE A two-character code for the continent associated with the IP address. The possible codes are: - **AF** - Africa - **AS** - Asia - **EU** - Europe - **NA** - North America - **OC** - Oceania - **SA** - South America #### GEOIP_COUNTRY_CODE A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) country code for the country associated with the IP address. In addition to the standard codes, we may also return one of the following: - **A1** - an [anonymous proxy](/?p=384). - **A2** - a [satellite provider](/?p=385). - **EU** - an IP in a block used by multiple [European](/?p=386) countries. - **AP** - an IP in a block used by multiple [Asia/Pacific region](/?p=386) countries. The **US** country code is returned for IP addresses associated with overseas US military bases. #### GEOIP_COUNTRY_NAME The country name associated with the IP address. ### GeoIP Region Edition Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_COUNTRY_CODE A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) country code for the country associated with the IP address. In addition to the standard codes, we may also return one of the following: - **A1** - an [anonymous proxy](/?page_id=23#anonproxy). - **A2** - a [satellite provider](/?page_id=23#satellite). - **EU** - an IP in a block used by multiple [European](/?page_id=23#euapcodes) countries. - **AP** - an IP in a block used by multiple [Asia/Pacific region](/?page_id=23#euapcodes) countries. The **US** country code is returned for IP addresses associated with overseas US military bases. #### GEOIP_REGION_NAME The region name associated with the IP address. #### GEOIP_REGION A two character [ISO-3166-2](http://en.wikipedia.org/wiki/ISO_3166-2) or [FIPS 10-4](http://en.wikipedia.org/wiki/FIPS_10-4) code for the state/region associated with the IP address. For the US and Canada, we return an ISO-3166-2 code. In addition to the standard ISO codes, we may also return one of the following: - **AA** - Armed Forces America - **AE** - Armed Forces Europe - **AP** - Armed Forces Pacific We return a FIPS code for all other countries. We provide a [CSV file which maps our region codes to region names](http://www.maxmind.com/download/geoip/misc/region_codes.csv). The columns are ISO country code, region code (FIPS or ISO), and the region name. ### GeoIP City Edition Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_CONTINENT_CODE A two-character code for the continent associated with the IP address. The possible codes are: - **AF** - Africa - **AS** - Asia - **EU** - Europe - **NA** - North America - **OC** - Oceania - **SA** - South America #### GEOIP_COUNTRY_CODE A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) country code for the country associated with the IP address. In addition to the standard codes, we may also return one of the following: - **A1** - an [anonymous proxy](/?page_id=23#anonproxy). - **A2** - a [satellite provider](/?page_id=23#satellite). - **EU** - an IP in a block used by multiple [European](/?page_id=23#euapcodes) countries. - **AP** - an IP in a block used by multiple [Asia/Pacific region](/?page_id=23#euapcodes) countries. The **US** country code is returned for IP addresses associated with overseas US military bases. #### GEOIP_REGION A two character [ISO-3166-2](http://en.wikipedia.org/wiki/ISO_3166-2) or [FIPS 10-4](http://en.wikipedia.org/wiki/FIPS_10-4) code for the state/region associated with the IP address. For the US and Canada, we return an ISO-3166-2 code. In addition to the standard ISO codes, we may also return one of the following: - **AA** - Armed Forces America - **AE** - Armed Forces Europe - **AP** - Armed Forces Pacific We return a FIPS code for all other countries. We provide a [CSV file which maps our region codes to region names](http://www.maxmind.com/download/geoip/misc/region_codes.csv). The columns are ISO country code, region code (FIPS or ISO), and the region name. #### GEOIP_REGION_NAME The region name associated with the IP address. #### GEOIP_CITY The city or town name associated with the IP address. See our [list of cities](http://www.maxmind.com/GeoIPCity-534-Location.csv) to see all the possible return values. This list is updated on a regular basis. #### GEOIP_METRO_CODE The metro code associated with the IP address. These are only available for IP addresses in the US. MaxMind returns the [same metro codes as the Google AdWords API](https://developers.google.com/adwords/api/docs/appendix/cities-DMAregions). #### GEOIP_AREA_CODE The telephone area code associated with the IP address. These are only available for IP addresses in the US. #### GEOIP_LATITUDE The latitude associated with the IP address. #### GEOIP_LONGITUDE The longitude associated with the IP address. #### GEOIP_POSTAL_CODE The postal code associated with the IP address. These are available for some IP addresses in the US, Canada, Germany, and United Kingdom. ### GeoIP ISP Edition Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_ISP The name of the ISP associated with the IP address. ### GeoIP Organization Edition Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_ORGANIZATION The name of the organization associated with the IP address. ### GeoIP Netspeed Edition Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_NETSPEED The network speed associated with the IP address. This can be one of the following values: - **Dialup** - **Cable/DSL** - **Corporate** - **Cellular** ### GeoIPv6 Edition (experimental) Output Variables #### GEOIP_ADDR The address used to calculate the GeoIP output. #### GEOIP_CONTINENT_CODE_V6 A two-character code for the continent associated with the IP address. The possible codes are: - **AF** - Africa - **AS** - Asia - **EU** - Europe - **NA** - North America - **OC** - Oceania - **SA** - South America #### GEOIP_COUNTRY_CODE_V6 A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) country code for the country associated with the IP address. In addition to the standard codes, we may also return one of the following: - **A1** - an [anonymous proxy](/?page_id=23#anonproxy). - **A2** - a [satellite provider](/?page_id=23#satellite). - **EU** - an IP in a block used by multiple [European](/?page_id=23#euapcodes) countries. - **AP** - an IP in a block used by multiple [Asia/Pacific region](/?page_id=23#euapcodes) countries. The **US** country code is returned for IP addresses associated with overseas US military bases. #### GEOIP_COUNTRY_NAME_V6 The country name associated with the IP address. Examples -------- Here are some examples of how you can use mod_geoip2. ### Redirecting a client based on country This example show you how to redirect a client based on the country code that GeoIP sets. GeoIPEnable On GeoIPDBFile /path/to/GeoIP.dat # Redirect one country RewriteEngine on RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^CA$ RewriteRule ^(.*)$ http://www.canada.com$1 [R,L] # Redirect multiple countries to a single page RewriteEngine on RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^(CA|US|MX)$ RewriteRule ^(.*)$ http://www.northamerica.com$1 [R,L] ### Blocking a client based on country This example show you how to block clients based on the country code that GeoIP sets. 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 ### Allowing clients based on country This example show you how to allow only clients from specific countries. GeoIPEnable On GeoIPDBFile /path/to/GeoIP.dat SetEnvIf GEOIP_COUNTRY_CODE US AllowCountry SetEnvIf GEOIP_COUNTRY_CODE CA AllowCountry SetEnvIf GEOIP_COUNTRY_CODE MX AllowCountry # ... place more countries here Deny from all Allow from env=AllowCountry ### Server vs Directory context All directives except GeoIPEnable are server config only, i.e., you type it only once per server config. Otherwise the latest wins. ``` {.lang:default .decode:true} GeoIPEnable Off GeoIPEnableUTF8 On GeoIPOutput Env GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache GeoIPDBFile /usr/local/share/GeoIP/GeoIPCity.dat MemoryCache GeoIPDBFile /usr/local/share/GeoIP/GeoIPOrg.dat MemoryCache ``` GeoIPEnable is useful in server or directory context. For example: GeoIP is only available for a specific location: ``` {.lang:default .decode:true} GeoIPEnable Off GeoIPEnableUTF8 On GeoIPOutput Env GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache # GeoIP information is avail only inside /xxx GeoIPEnable On ... ... ``` GeoIP is available for all locations: ``` {.lang:default .decode:true} GeoIPEnable On GeoIPEnableUTF8 On GeoIPOutput Env GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache # This doesn't work, because it's already been enabled in the server-wide # config! GeoIPEnable On GeoIPEnable Off ``` Memory Usage ------------ Starting with mod_geoip2 version 1.2.1, all Apache child processes share the same database when you set the MemoryCache or MMapCache flag. Memory usage is about the same as the database file size, no matter how many child processes Apache spawns. The only thing to remember is ask Apache to update if your database changes. Use the graceful restart option to do so without stopping Apache. Performance ----------- For improved performance, you may want to enable mod_geoip only for specific HTML pages. If you want to use the mod_geoip module site-wide, you may still be able to only use it for HTML pages and not images. To restrict the pages where mod_geoip2 is used, place the `GeoIPEnable On` directive inside a , or directive, see: [httpd.apache.org/docs/2.0/sections.html](http://httpd.apache.org/docs/2.0/sections.html) Troubleshooting --------------- If the module is not working, make sure that the httpd user (e.g. nobody) has read access to the GeoIP database file(s) you are using. If the GeoIP variables do not show up please make sure that the client IP address is not on a private network such as 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16. GeoIP can only look up public IP addresses. ------ This file was generated by running pandoc --from html --to markdown Using the pre-generated HTML from http://dev.maxmind.com/geoip/legacy/mod_geoip2 as the input. geoip-api-mod_geoip2-1.2.10/README.php000066400000000000000000000012751247636344400171570ustar00rootroot00000000000000To use from PHP, use something like: GeoIP Country: GeoIP Region: GeoIP City: ================================================== Redirection with PHP $country_code = apache_note("GEOIP_COUNTRY_CODE"); if ( $country_code == "DE" ) { header ("Location: http://www.google.de" ); } else { header ("Location: http://www.yoursite.com" ); } geoip-api-mod_geoip2-1.2.10/mod_geoip.c000066400000000000000000001002401247636344400176070ustar00rootroot00000000000000/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2004 MaxMind, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * MaxMind (http://www.maxmind.com/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "MaxMind" and "GeoIP" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact support@maxmind.com. * * 5. Products derived from this software may not be called "GeoIP", * nor may "MaxMind" appear in their name, without prior written * permission of the MaxMind. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * */ /* This module sets an environment variable to the remote country * based on the requester's IP address. It uses the GeoIP library * to lookup the country by IP address. */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "http_log.h" #include "ap_config.h" #include "apr_strings.h" #include "util_script.h" #include #include "GeoIP.h" #include "GeoIPCity.h" typedef struct { int GeoIPEnabled; } geoip_dir_config_rec; typedef struct { GeoIP **gips; int numGeoIPFiles; char **GeoIPFilenames; int GeoIPEnabled; int GeoIPEnableUTF8; char GeoIPOutput; int GeoIPFlags; int *GeoIPFlags2; int scanProxyHeaders; int proxyHeaderMode; char *GeoIPProxyField; } geoip_server_config_rec; static const int GEOIP_PROXY_HEADER_MODE_FIRST_IP = 0; static const int GEOIP_PROXY_HEADER_MODE_LAST_IP = 1; static const int GEOIP_PROXY_HEADER_MODE_FIRST_NON_PRIVATE_IP = 2; static const int GEOIP_PROXY_HEADER_MODE_DEFAULT = 0; static const int GEOIP_NONE = 0; static const int GEOIP_DEFAULT = 1; static const int GEOIP_NOTES = 2; static const int GEOIP_ENV = 4; static const int GEOIP_REQUEST = 8; static const int GEOIP_ALL = 14; static const int GEOIP_INIT = 15; static const int GEOIP_UNKNOWN = -1; char metrocodestr[100]; char areacodestr[100]; char latstr[100]; char lonstr[100]; const char *netspeedstring; module AP_MODULE_DECLARE_DATA geoip_module; uint32_t _private_ipv4_networks[] = { 167772160U, 184549375U, // 10.0.0.0/8 1681915904U, 1686110207U, // 100.64.0.0/10 2130706432U, 2147483647U, // 127.0.0.0/8 2886729728U, 2887778303U, // 172.16.0.0/12 3221225984U, 3221226239U, // 192.0.2.0/24 3227017984U, 3227018239U, // 192.88.99.0/24 3232235520U, 3232301055U, // 192.168.0.0/16 2851995648U, 2852061183U, // 169.254.0.0/16 0U, 0U }; static int _is_private(uint32_t ipnum) { uint32_t min, max; uint32_t *p = _private_ipv4_networks; while ((min = *p++)) { max = *p++; if (ipnum < min || ipnum > max) { continue; } return 1; } return 0; } char *_get_ip_from_xff(request_rec *r, const char *xffheader) { char *xff = apr_pstrdup(r->pool, xffheader); char *xff_ip, *break_ptr; uint32_t ipnum; if (xff) { for (xff_ip = strtok_r(xff, " \t,", &break_ptr); xff_ip; xff_ip = strtok_r(NULL, " \t,", &break_ptr)) { if (1 != inet_pton(AF_INET, xff_ip, &ipnum)) { continue; } ipnum = htonl(ipnum); if (!_is_private(ipnum)) { char *found = apr_pstrdup(r->pool, xff_ip); return found; } } } return NULL; } /* create a disabled directory entry */ static void *geoip_create_dir_config(apr_pool_t * p, char *d) { geoip_dir_config_rec *dcfg; dcfg = (geoip_dir_config_rec *)apr_pcalloc(p, sizeof(geoip_dir_config_rec)); dcfg->GeoIPEnabled = 0; return dcfg; } static apr_status_t geoip_cleanup(void *cfgdata) { int i; geoip_server_config_rec *cfg = (geoip_server_config_rec *)cfgdata; if (cfg->gips) { for (i = 0; i < cfg->numGeoIPFiles; i++) { if (cfg->gips[i]) { GeoIP_delete(cfg->gips[i]); cfg->gips[i] = NULL; } } } return APR_SUCCESS; } /* initialize geoip any server ( any virtual server! ) */ static void geoip_server_init(apr_pool_t * p, server_rec * s) { geoip_server_config_rec *cfg; int i; while (s) { cfg = (geoip_server_config_rec *) ap_get_module_config(s->module_config, &geoip_module); if (!cfg->gips) { if (cfg->GeoIPFilenames != NULL) { cfg->gips = apr_pcalloc(p, sizeof(GeoIP *) * cfg->numGeoIPFiles); for (i = 0; i < cfg->numGeoIPFiles; i++) { cfg->gips[i] = GeoIP_open(cfg->GeoIPFilenames[i], (cfg->GeoIPFlags2[i] == GEOIP_UNKNOWN) ? cfg->GeoIPFlags : cfg->GeoIPFlags2[i]); if (cfg->gips[i]) { if (cfg->GeoIPEnableUTF8) { GeoIP_set_charset(cfg->gips[i], GEOIP_CHARSET_UTF8); } } else { ap_log_error( APLOG_MARK, APLOG_ERR, 0, s, "[mod_geoip]: Error while opening data file %s", cfg->GeoIPFilenames[i]); continue; } } } else { cfg->gips = apr_pcalloc(p, sizeof(GeoIP *)); cfg->gips[0] = GeoIP_new(GEOIP_STANDARD); if (!cfg->gips[0]) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "[mod_geoip]: Error while opening data file"); } cfg->numGeoIPFiles = 1; } apr_pool_cleanup_register(p, (void *)cfg, geoip_cleanup, geoip_cleanup); } s = s->next; } } static void geoip_child_init(apr_pool_t * p, server_rec * s) { geoip_server_config_rec *cfg; int i, flags; while (s) { cfg = (geoip_server_config_rec *) ap_get_module_config(s->module_config, &geoip_module); if (cfg->gips) { if (cfg->GeoIPFilenames != NULL) { for (i = 0; i < cfg->numGeoIPFiles; i++) { flags = (cfg->GeoIPFlags2[i] == GEOIP_UNKNOWN) ? cfg->GeoIPFlags : cfg->GeoIPFlags2[i]; if (cfg->gips[i]) { GeoIP_delete(cfg->gips[i]); } cfg->gips[i] = GeoIP_open(cfg->GeoIPFilenames[i], flags); if (cfg->gips[i]) { if (cfg->GeoIPEnableUTF8) { GeoIP_set_charset(cfg->gips[i], GEOIP_CHARSET_UTF8); } } else { ap_log_error( APLOG_MARK, APLOG_ERR, 0, s, "[mod_geoip]: Error while opening data file %s", cfg->GeoIPFilenames[i]); continue; } } } else { if (cfg->gips[0]) { GeoIP_delete(cfg->gips[0]); } cfg->gips[0] = GeoIP_new(GEOIP_STANDARD); if (!cfg->gips[0]) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "[mod_geoip]: Error while opening data file"); } cfg->numGeoIPFiles = 1; } apr_pool_cleanup_register(p, (void *)cfg, geoip_cleanup, geoip_cleanup); } s = s->next; } } /* map into the first apache */ static int geoip_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * s) { geoip_server_init(p, s); return OK; } static int geoip_header_parser(request_rec * r); static int geoip_post_read_request(request_rec * r) { geoip_server_config_rec *cfg; cfg = ap_get_module_config(r->server->module_config, &geoip_module); if (!cfg) { return DECLINED; } if (!cfg->GeoIPEnabled) { return DECLINED; } return geoip_header_parser(r); } static int geoip_per_dir(request_rec * r) { geoip_dir_config_rec *dcfg; geoip_server_config_rec *cfg = ap_get_module_config(r->server->module_config, &geoip_module); if (cfg && cfg->GeoIPEnabled) { return DECLINED; } dcfg = ap_get_module_config(r->per_dir_config, &geoip_module); if (!dcfg) { return DECLINED; } if (!dcfg->GeoIPEnabled) { return DECLINED; } return geoip_header_parser(r); } char *_get_client_ip(request_rec * r) { # if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER == 4 return r->useragent_ip; # else return r->connection->remote_ip; #endif } static void geoip_say(geoip_server_config_rec * cfg, request_rec * r, const char *key, const char *value) { if (value) { if (cfg->GeoIPOutput & GEOIP_NOTES) { apr_table_set(r->notes, key, value); } if (cfg->GeoIPOutput & GEOIP_ENV) { apr_table_set(r->subprocess_env, key, value); } if (cfg->GeoIPOutput & GEOIP_REQUEST) { apr_table_set(r->headers_in, key, value); } } } static int geoip_header_parser(request_rec * r) { char *orgorisp; char *ipaddr; short int country_id; const char *continent_code; const char *country_code; const char *country_name; const char *region_name = NULL; geoip_server_config_rec *cfg; unsigned char databaseType; GeoIPRecord *gir; GeoIPRegion *giregion; int i; int netspeed; /* For splitting proxy headers */ char *ipaddr_ptr = NULL; char *comma_ptr; cfg = ap_get_module_config(r->server->module_config, &geoip_module); if (!cfg) { return DECLINED; } if (!cfg->scanProxyHeaders) { ipaddr = _get_client_ip(r); } else { ap_add_common_vars(r); if (cfg->GeoIPProxyField) { ipaddr_ptr = (char *)apr_table_get(r->headers_in, cfg->GeoIPProxyField); } else if (apr_table_get(r->subprocess_env, "HTTP_CLIENT_IP")) { ipaddr_ptr = (char *)apr_table_get(r->subprocess_env, "HTTP_CLIENT_IP"); } else if (apr_table_get(r->subprocess_env, "HTTP_X_FORWARDED_FOR")) { ipaddr_ptr = (char *)apr_table_get(r->subprocess_env, "HTTP_X_FORWARDED_FOR"); } else if (apr_table_get(r->headers_in, "X-Forwarded-For")) { ipaddr_ptr = (char *)apr_table_get(r->headers_in, "X-Forwarded-For"); } else if (apr_table_get(r->subprocess_env, "HTTP_REMOTE_ADDR")) { ipaddr_ptr = (char *)apr_table_get(r->subprocess_env, "HTTP_REMOTE_ADDR"); } if (!ipaddr_ptr) { ap_log_error( APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, "[mod_geoip]: Error while getting ipaddr from proxy headers. Using REMOTE_ADDR."); ipaddr = _get_client_ip(r); } else { /* Found XFF like header */ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, "[mod_geoip]: IPADDR_PTR: %s", ipaddr_ptr); if (cfg->proxyHeaderMode == GEOIP_PROXY_HEADER_MODE_FIRST_NON_PRIVATE_IP) { ipaddr = _get_ip_from_xff(r, ipaddr_ptr); if (!ipaddr) { ipaddr = _get_client_ip(r); } } else { ipaddr = (char *)apr_pcalloc(r->pool, 8 * 4 + 7 + 1); /* proxyHeaderMode is * GEOIP_PROXY_HEADER_MODE_LAST_IP or GEOIP_PROXY_HEADER_MODE_FIRST_IP */ /* * Check to ensure that the HTTP_CLIENT_IP or * X-Forwarded-For header is not a comma separated * list of addresses, which would cause mod_geoip to * return no country code. If the header is a comma * separated list, return the first IP address in the * list, which is (hopefully!) the real client IP. */ if (cfg->proxyHeaderMode == GEOIP_PROXY_HEADER_MODE_LAST_IP) { comma_ptr = strrchr(ipaddr_ptr, ','); if (comma_ptr) { /* skip over whitespace */ ipaddr_ptr = comma_ptr + strspn(comma_ptr, ", \t"); } } strncpy(ipaddr, ipaddr_ptr, 8 * 4 + 7); comma_ptr = strchr(ipaddr, ','); if (comma_ptr != 0) { *comma_ptr = '\0'; } } } } geoip_say(cfg, r, "GEOIP_ADDR", ipaddr); for (i = 0; i < cfg->numGeoIPFiles; i++) { /* * skip database handles that can not be opned for some * reason */ if (cfg->gips[i] == NULL) { continue; } databaseType = cfg->gips[i] ? GeoIP_database_edition(cfg->gips[i]) : -1; /* -1 is "magic value" * in case file not * found */ switch (databaseType) { case GEOIP_NETSPEED_EDITION_REV1: orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); geoip_say(cfg, r, "GEOIP_NETSPEED", orgorisp); free(orgorisp); break; case GEOIP_NETSPEED_EDITION: netspeed = GeoIP_id_by_addr(cfg->gips[i], ipaddr); if (netspeed == GEOIP_UNKNOWN_SPEED) { netspeedstring = "unknown"; } else if (netspeed == GEOIP_DIALUP_SPEED) { netspeedstring = "dialup"; } else if (netspeed == GEOIP_CABLEDSL_SPEED) { netspeedstring = "cabledsl"; } else if (netspeed == GEOIP_CORPORATE_SPEED) { netspeedstring = "corporate"; } geoip_say(cfg, r, "GEOIP_NETSPEED", netspeedstring); break; case GEOIP_COUNTRY_EDITION_V6: /* Get the Country ID */ country_id = GeoIP_id_by_addr_v6(cfg->gips[i], ipaddr); if (country_id > 0) { /* Lookup the Code and the Name with the ID */ continent_code = GeoIP_country_continent[country_id]; country_code = GeoIP_country_code[country_id]; country_name = GeoIP_country_name[country_id]; if (cfg->numGeoIPFiles == 0) { cfg->numGeoIPFiles = 0; } if (cfg->GeoIPFilenames == 0) { cfg->GeoIPFilenames = 0; } /* Set it for our user */ geoip_say(cfg, r, "GEOIP_CONTINENT_CODE_V6", continent_code); geoip_say(cfg, r, "GEOIP_COUNTRY_CODE_V6", country_code); geoip_say(cfg, r, "GEOIP_COUNTRY_NAME_V6", country_name); } break; case GEOIP_COUNTRY_EDITION: /* Get the Country ID */ country_id = GeoIP_country_id_by_addr(cfg->gips[i], ipaddr); if (country_id > 0) { /* Lookup the Code and the Name with the ID */ continent_code = GeoIP_country_continent[country_id]; country_code = GeoIP_country_code[country_id]; country_name = GeoIP_country_name[country_id]; if (cfg->numGeoIPFiles == 0) { cfg->numGeoIPFiles = 0; } if (cfg->GeoIPFilenames == 0) { cfg->GeoIPFilenames = 0; } /* Set it for our user */ geoip_say(cfg, r, "GEOIP_CONTINENT_CODE", continent_code); geoip_say(cfg, r, "GEOIP_COUNTRY_CODE", country_code); geoip_say(cfg, r, "GEOIP_COUNTRY_NAME", country_name); } break; case GEOIP_REGION_EDITION_REV0: case GEOIP_REGION_EDITION_REV1: giregion = GeoIP_region_by_name(cfg->gips[i], ipaddr); if (giregion != NULL) { if (giregion->country_code[0]) { region_name = GeoIP_region_name_by_code (giregion->country_code, giregion->region); geoip_say(cfg, r, "GEOIP_COUNTRY_CODE", giregion->country_code); country_id = GeoIP_id_by_code(giregion->country_code); geoip_say(cfg, r, "GEOIP_COUNTRY_NAME", GeoIP_country_name[country_id]); geoip_say(cfg, r, "GEOIP_CONTINENT_CODE", GeoIP_country_continent[country_id]); } if (giregion->region[0]) { geoip_say(cfg, r, "GEOIP_REGION", giregion->region); } if (region_name != NULL) { geoip_say(cfg, r, "GEOIP_REGION_NAME", region_name); } GeoIPRegion_delete(giregion); } break; case GEOIP_CITY_EDITION_REV0_V6: case GEOIP_CITY_EDITION_REV1_V6: gir = GeoIP_record_by_addr_v6(cfg->gips[i], ipaddr); if (gir != NULL) { if (gir->country_code != NULL) { region_name = GeoIP_region_name_by_code(gir->country_code, gir->region); } sprintf(metrocodestr, "%d", gir->dma_code); sprintf(areacodestr, "%d", gir->area_code); geoip_say(cfg, r, "GEOIP_CONTINENT_CODE_V6", gir->continent_code); geoip_say(cfg, r, "GEOIP_COUNTRY_CODE_V6", gir->country_code); geoip_say(cfg, r, "GEOIP_COUNTRY_NAME_V6", gir->country_name); geoip_say(cfg, r, "GEOIP_REGION_V6", gir->region); geoip_say(cfg, r, "GEOIP_REGION_NAME_V6", region_name); geoip_say(cfg, r, "GEOIP_CITY_V6", gir->city); geoip_say(cfg, r, "GEOIP_DMA_CODE_V6", metrocodestr); geoip_say(cfg, r, "GEOIP_METRO_CODE_V6", metrocodestr); geoip_say(cfg, r, "GEOIP_AREA_CODE_V6", areacodestr); sprintf(latstr, "%f", gir->latitude); sprintf(lonstr, "%f", gir->longitude); geoip_say(cfg, r, "GEOIP_LATITUDE_V6", latstr); geoip_say(cfg, r, "GEOIP_LONGITUDE_V6", lonstr); geoip_say(cfg, r, "GEOIP_POSTAL_CODE_V6", gir->postal_code); GeoIPRecord_delete(gir); } break; case GEOIP_CITY_EDITION_REV0: case GEOIP_CITY_EDITION_REV1: gir = GeoIP_record_by_addr(cfg->gips[i], ipaddr); if (gir != NULL) { if (gir->country_code != NULL) { region_name = GeoIP_region_name_by_code(gir->country_code, gir->region); } sprintf(metrocodestr, "%d", gir->dma_code); sprintf(areacodestr, "%d", gir->area_code); geoip_say(cfg, r, "GEOIP_CONTINENT_CODE", gir->continent_code); geoip_say(cfg, r, "GEOIP_COUNTRY_CODE", gir->country_code); geoip_say(cfg, r, "GEOIP_COUNTRY_NAME", gir->country_name); geoip_say(cfg, r, "GEOIP_REGION", gir->region); geoip_say(cfg, r, "GEOIP_REGION_NAME", region_name); geoip_say(cfg, r, "GEOIP_CITY", gir->city); geoip_say(cfg, r, "GEOIP_DMA_CODE", metrocodestr); geoip_say(cfg, r, "GEOIP_METRO_CODE", metrocodestr); geoip_say(cfg, r, "GEOIP_AREA_CODE", areacodestr); sprintf(latstr, "%f", gir->latitude); sprintf(lonstr, "%f", gir->longitude); geoip_say(cfg, r, "GEOIP_LATITUDE", latstr); geoip_say(cfg, r, "GEOIP_LONGITUDE", lonstr); geoip_say(cfg, r, "GEOIP_POSTAL_CODE", gir->postal_code); GeoIPRecord_delete(gir); } break; case GEOIP_ORG_EDITION: orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); geoip_say(cfg, r, "GEOIP_ORGANIZATION", orgorisp); free(orgorisp); break; case GEOIP_ISP_EDITION: orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); geoip_say(cfg, r, "GEOIP_ISP", orgorisp); free(orgorisp); break; case GEOIP_DOMAIN_EDITION: orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); geoip_say(cfg, r, "GEOIP_DOMAIN", orgorisp); free(orgorisp); break; } } return OK; } static const char *geoip_scanproxyfield(cmd_parms * cmd, void *dummy, const char *field) { geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!field) { return NULL; } conf->GeoIPProxyField = (char *)apr_pstrdup(cmd->pool, field); return NULL; } static const char *geoip_use_first_non_private_x_forwarded_for_ip(cmd_parms * cmd, void *dummy, int arg) { geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!conf) { return "mod_geoip: server structure not allocated"; } conf->proxyHeaderMode = arg ? GEOIP_PROXY_HEADER_MODE_FIRST_NON_PRIVATE_IP : GEOIP_PROXY_HEADER_MODE_DEFAULT; return NULL; } static const char *geoip_use_first_x_forwarded_for_ip(cmd_parms * cmd, void *dummy, int arg) { geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!conf) { return "mod_geoip: server structure not allocated"; } conf->proxyHeaderMode = arg ? GEOIP_PROXY_HEADER_MODE_FIRST_IP : GEOIP_PROXY_HEADER_MODE_DEFAULT; return NULL; } static const char *geoip_use_last_x_forwarded_for_ip(cmd_parms * cmd, void *dummy, int arg) { geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!conf) { return "mod_geoip: server structure not allocated"; } conf->proxyHeaderMode = arg ? GEOIP_PROXY_HEADER_MODE_LAST_IP : GEOIP_PROXY_HEADER_MODE_DEFAULT; return NULL; } static const char *geoip_scanproxy(cmd_parms * cmd, void *dummy, int arg) { geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!conf) { return "mod_geoip: server structure not allocated"; } conf->scanProxyHeaders = arg; return NULL; } static const char *set_geoip_enable(cmd_parms * cmd, void *dummy, int arg) { geoip_server_config_rec *conf; /* is per directory config? */ if (cmd->path) { geoip_dir_config_rec *dcfg = dummy; dcfg->GeoIPEnabled = arg; return NULL; } /* no then it is server config */ conf = (geoip_server_config_rec *) ap_get_module_config(cmd->server->module_config, &geoip_module); if (!conf) { return "mod_geoip: server structure not allocated"; } conf->GeoIPEnabled = arg; return NULL; } static const char *set_geoip_enable_utf8(cmd_parms * cmd, void *dummy, int arg) { geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!conf) { return "mod_geoip: server structure not allocated"; } conf->GeoIPEnableUTF8 = arg; return NULL; } static const char *set_geoip_filename(cmd_parms * cmd, void *dummy, const char *filename, const char *arg2) { int i; geoip_server_config_rec *conf = (geoip_server_config_rec *) ap_get_module_config( cmd->server->module_config, &geoip_module); if (!filename) { return NULL; } i = conf->numGeoIPFiles; conf->numGeoIPFiles++; conf->GeoIPFilenames = realloc(conf->GeoIPFilenames, conf->numGeoIPFiles * sizeof(char *)); conf->GeoIPFilenames[i] = (char *)apr_pstrdup(cmd->pool, filename); conf->GeoIPFlags2 = realloc(conf->GeoIPFlags2, conf->numGeoIPFiles * sizeof(int)); if (arg2 == NULL) { conf->GeoIPFlags2[i] = GEOIP_UNKNOWN; } else if (!strcmp(arg2, "Standard")) { conf->GeoIPFlags2[i] = GEOIP_STANDARD; } else if (!strcmp(arg2, "MemoryCache")) { conf->GeoIPFlags2[i] = GEOIP_MEMORY_CACHE; } else if (!strcmp(arg2, "CheckCache")) { conf->GeoIPFlags2[i] = GEOIP_CHECK_CACHE; } else if (!strcmp(arg2, "IndexCache")) { conf->GeoIPFlags2[i] = GEOIP_INDEX_CACHE; } else if (!strcmp(arg2, "MMapCache")) { conf->GeoIPFlags2[i] = GEOIP_MMAP_CACHE; } return NULL; } static const char *set_geoip_output_mode(cmd_parms * cmd, void *dummy, const char *arg) { geoip_server_config_rec *cfg = (geoip_server_config_rec *)ap_get_module_config(cmd-> server->module_config, &geoip_module); if (cfg->GeoIPOutput & GEOIP_DEFAULT) { /* was set to default, clear so can be reset with user specified values */ cfg->GeoIPOutput = GEOIP_NONE; } if (!strcmp(arg, "Notes")) { cfg->GeoIPOutput |= GEOIP_NOTES; } else if (!strcmp(arg, "Env")) { cfg->GeoIPOutput |= GEOIP_ENV; } else if (!strcmp(arg, "Request")) { cfg->GeoIPOutput |= GEOIP_REQUEST; } else if (!strcmp(arg, "All")) { cfg->GeoIPOutput |= GEOIP_ALL; } return NULL; } static void *make_geoip(apr_pool_t * p, server_rec * d) { geoip_server_config_rec *dcfg; dcfg = (geoip_server_config_rec *)apr_pcalloc(p, sizeof (geoip_server_config_rec)); dcfg->gips = NULL; dcfg->numGeoIPFiles = 0; dcfg->GeoIPFilenames = NULL; dcfg->GeoIPEnabled = 0; dcfg->GeoIPEnableUTF8 = 0; dcfg->GeoIPOutput = GEOIP_INIT; dcfg->GeoIPFlags = GEOIP_STANDARD; dcfg->GeoIPFlags2 = NULL; return dcfg; } static const command_rec geoip_cmds[] = { AP_INIT_FLAG("GeoIPScanProxyHeaders", geoip_scanproxy, NULL, RSRC_CONF, "Get IP from HTTP_CLIENT IP or X-Forwarded-For"), AP_INIT_TAKE1("GeoIPScanProxyHeaderField", geoip_scanproxyfield, NULL, RSRC_CONF, "Get IP from this header field, only"), AP_INIT_FLAG( "GeoIPUseFirstNonPrivateXForwardedForIP", geoip_use_first_non_private_x_forwarded_for_ip, NULL, RSRC_CONF, "For more IP's in X-Forwarded-For, use the first non private IP"), AP_INIT_FLAG("GeoIPUseFirstXForwardedForIP", geoip_use_first_x_forwarded_for_ip, NULL, RSRC_CONF, "For more IP's in X-Forwarded-For, use the first"), AP_INIT_FLAG("GeoIPUseLastXForwardedForIP", geoip_use_last_x_forwarded_for_ip, NULL, RSRC_CONF, "For more IP's in X-Forwarded-For, use the last"), AP_INIT_FLAG("GeoIPEnable", set_geoip_enable, NULL, RSRC_CONF | OR_FILEINFO, "Turn on mod_geoip"), AP_INIT_FLAG("GeoIPEnableUTF8", set_geoip_enable_utf8, NULL, RSRC_CONF, "Turn on utf8 characters for city names"), AP_INIT_TAKE12("GeoIPDBFile", set_geoip_filename, NULL, RSRC_CONF, "Path to GeoIP Data File"), AP_INIT_ITERATE("GeoIPOutput", set_geoip_output_mode, NULL, RSRC_CONF, "Specify output method(s)"), { NULL } }; static void geoip_register_hooks(apr_pool_t * p) { /* make sure we run before mod_rewrite's handler */ static const char *const aszSucc[] = { "mod_setenvif.c", "mod_rewrite.c", NULL }; /* we have two entry points, the header_parser hook, right before * the authentication hook used for Dirctory specific enabled geoiplookups * or right before directory rewrite rules. */ ap_hook_header_parser(geoip_per_dir, NULL, aszSucc, APR_HOOK_FIRST); /* and the servectly wide hook, after reading the request. Perfecly * suitable to serve serverwide mod_rewrite actions */ ap_hook_post_read_request(geoip_post_read_request, NULL, aszSucc, APR_HOOK_MIDDLE); /* setup our childs GeoIP database once for every child */ ap_hook_child_init(geoip_child_init, NULL, NULL, APR_HOOK_MIDDLE); /* static const char * const list[]={ "mod_geoip.c", NULL }; */ /* mmap the database(s) into the master process */ ap_hook_post_config(geoip_post_config, NULL, NULL, APR_HOOK_MIDDLE); } /* Dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA geoip_module = { STANDARD20_MODULE_STUFF, geoip_create_dir_config, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ make_geoip, /* create per-server config structures */ NULL, /* merge per-server config structures */ geoip_cmds, /* table of config file commands */ geoip_register_hooks /* register hooks */ };