├── .uncrustify.cfg ├── Changes ├── INSTALL.md ├── LICENSE ├── README.md ├── README.php └── mod_geoip.c /.uncrustify.cfg: -------------------------------------------------------------------------------- 1 | # 2 | # based on uncrustify config file for the linux kernel 3 | # 4 | 5 | code_width = 80 6 | indent_case_brace = 4 7 | indent_columns = 4 8 | indent_label = 2 # pos: absolute col, neg: relative column 9 | indent_with_tabs = 0 10 | 11 | # 12 | # inter-symbol newlines 13 | # 14 | nl_brace_else = remove # "} else" vs "} \n else" - cuddle else 15 | nl_brace_while = remove # "} while" vs "} \n while" - cuddle while 16 | nl_do_brace = remove # "do {" vs "do \n {" 17 | nl_else_brace = remove # "else {" vs "else \n {" 18 | nl_enum_brace = remove # "enum {" vs "enum \n {" 19 | nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{" 20 | nl_fdef_brace = force # "int foo() {" vs "int foo()\n{" 21 | nl_for_brace = remove # "for () {" vs "for () \n {" 22 | nl_func_var_def_blk = 0 # don't add newlines after a block of var declarations 23 | nl_if_brace = remove # "if () {" vs "if () \n {" 24 | nl_multi_line_define = true 25 | nl_struct_brace = remove # "struct {" vs "struct \n {" 26 | nl_switch_brace = remove # "switch () {" vs "switch () \n {" 27 | nl_union_brace = remove # "union {" vs "union \n {" 28 | nl_while_brace = remove # "while () {" vs "while () \n {" 29 | 30 | 31 | # 32 | # Source code modifications 33 | # 34 | mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();" 35 | mod_full_brace_for = force # "for () a--;" vs "for () { a--; }" 36 | mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }" 37 | mod_full_brace_nl = 3 # don't remove if more than 3 newlines 38 | mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }" 39 | mod_paren_on_return = remove # "return 1;" vs "return (1);" 40 | 41 | 42 | # 43 | # inter-character spacing options 44 | # 45 | sp_after_cast = remove # "(int) a" vs "(int)a" 46 | sp_after_comma = force 47 | sp_after_sparen = force # "if () {" vs "if (){" 48 | sp_arith = force 49 | sp_assign = force 50 | sp_assign = force 51 | sp_before_comma = remove 52 | sp_before_ptr_star = force # "char *foo" vs "char* foo 53 | sp_before_sparen = force # "if (" vs "if(" 54 | sp_between_ptr_star = remove # "char * *foo" vs "char **foo" 55 | sp_bool = force 56 | sp_compare = force 57 | sp_func_call_paren = remove # "foo (" vs "foo(" 58 | sp_func_def_paren = remove # "int foo (){" vs "int foo(){" 59 | sp_func_proto_paren = remove # "int foo ();" vs "int foo();" 60 | sp_inside_braces = force # "{ 1 }" vs "{1}" 61 | sp_inside_braces_enum = force # "{ 1 }" vs "{1}" 62 | sp_inside_braces_struct = force # "{ 1 }" vs "{1}" 63 | sp_inside_sparen = remove 64 | sp_paren_brace = force 65 | sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)" 66 | 67 | # 68 | # Aligning stuff 69 | # 70 | align_enum_equ_span = 4 # '=' in enum definition 71 | align_nl_cont = true 72 | align_on_tabstop = FALSE # align on tabstops 73 | align_right_cmt_span = 3 74 | align_struct_init_span = 1 75 | align_struct_init_span = 3 # align stuff in a structure init '= { }' 76 | align_var_def_star_style = 2 # void *foo; 77 | align_var_struct_span = 0 78 | align_with_tabs = FALSE # use tabs to align 79 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | 1.2.10 2015-03-06 2 | 3 | - Update docs to note that GeoIP configuration directives cannot be placed 4 | in .htaccess files. 5 | - Fix small memleak (Boris Zentner) 6 | - A segfault when using multi-threaded workers was fixed. (Fix from thinker0. 7 | GitHub #16.) 8 | - Several instances of manual memory management were switched to use the 9 | use Apache's memory pool. (Fix from thinker0. GitHub #16.) 10 | 11 | 1.2.9 2014-03-20 12 | 13 | - Added a new directive, GeoIPScanProxyHeaderField, to specify a custom 14 | header which contains the client's IP address (Sascha Kuehndel) 15 | - Added the ability to forward the result fields to a backend server/proxy 16 | via request header (Sascha Kuehndel) 17 | 18 | 1.2.9 2013-01-08 19 | 20 | - Add GeoIPUseFirstNonPrivateXForwardedForIP option (Boris Zentner) 21 | - Support Apache 2.4 (Boris Zentner) 22 | - Use GeoIP_id_by_addr_v6 instead of GeoIP_country_id_by_addr_v6 (Boris Zentner) 23 | - Include util_script.h to silence warning about ap_add_common_vars (Boris Zentner) 24 | 25 | 1.2.7 2011-08-23 26 | 27 | - Add support for GEOIP_NETSPEED_REV1 (Boris Zentner) 28 | - Experimental support for GEOIP_COUNTRY_EDITION_V6 (Boris Zentner) 29 | - Add GEOIP_DOMAIN_EDITION support (Boris Zentner) 30 | 31 | 1.2.6 2008-09-11 32 | 33 | - GEOIP_METRO_CODE replace the depreciated GEOIP_DMA_CODE (Boris Zentner) 34 | 35 | 1.2.5 2008-08-13 36 | 37 | ! Fix GEOIP_REGION and GEOIP_COUNTRY_CODE when used with the GeoIPRegion 38 | database. Both are only set if a region or country was found. Previously 39 | a empty string was assigned to both (Boris Zentner) 40 | - Add GEOIP_REGION_NAME for City and Region databases (Boris Zentner) 41 | 42 | 1.2.4 2008-06-10 43 | 44 | ! mod_geoip2 has sets GEOIP_COUNTRY_CODE to -- for unknown countries when 45 | used with the country database. But for any other database (City for 46 | example) GEOIP_COUNTRY_CODE is unset for unknown countries. This is 47 | fixed now. Same for GEOIP_CONTINENT_CODE and GEOIP_COUNTRY_NAME. (Boris 48 | Zentner) 49 | - Add GEOIP_ADDR. That's the address used to compute the geoip 50 | information. Exported as env, notes or both as usual (Jason Caldwell) 51 | - Try to run always before mod_setenvif and mod_rewrite. (Boris Zentner) 52 | 53 | 1.2.3 2008-04-26 54 | 55 | - Skip files that we can not open for some reason (permission/typo). Check 56 | and skip empty slots in geoip_header_parser (Boris Zentner) 57 | - Slight performance increase - don't make per_dir ap_get_module_config 58 | call where we return DECLINED because cfg->GeoIPEnabled is true (Guenter 59 | Knauf) 60 | - NetWare/Win32 compilation fixes, since can't declare vars in middle of 61 | code (Guenter Knauf) 62 | 63 | 1.2.2 2008-03-18 64 | 65 | - Fix race condition for IO based caches like Standard. MMapCache and 66 | MemoryCache are not affected. (Boris Zentner) 67 | 68 | 1.2.1 2007-12-17 69 | 70 | ! Notice - all directives are _only_ valid in server context except 71 | GeoIPEnabled. Check you configuration with apachectl configtest (Boris 72 | Zentner) 73 | - Added MMapCache option (Boris Zentner) 74 | - Change GeoIPEnabled from a serverwide option to a 75 | server/directory/location keyword. (Boris Zentner) 76 | - Fix a small memleak per child. Allocated in geoip_child_init free in 77 | geoip_cleanup (Boris Zentner) 78 | - GeoIP databases get used serverwide now. Not per child. See the 79 | README. (Boris Zentner) 80 | - Update README with more examples (Boris Zentner) 81 | - Added support for UTF8 output for GeoIP City databases (Boris Zentner) 82 | 83 | 1.2.0 2007-08-30 84 | 85 | - Fix segfault issue if GeoIP.dat file cannot be opened (Vladimir 86 | Sedlacek) 87 | - Added support for GEOIP_CONTINENT_CODE for GeoIP Country and City (Frank 88 | Mather) 89 | - Added GeoIPScanProxyHeaders directive to handle X-Forwarded-For headers 90 | (Frank Mather) 91 | - Updated documentation to specify that GeoIPFlags need to be passed 92 | as second parameter to GeoIPDBFile, instead of using the GeoIPFlags directive 93 | 94 | 1.1.8 2006-04-28 95 | 96 | - Updated README file with GeoIPFlags docs and performance tips 97 | - Added apr_strings.h include (Dann Frazier, Fixes Debian #357387) 98 | - Added support for IndexCache 99 | 100 | 1.1.7 2005-08-01 101 | 102 | - Copied docs in mod_geoip1.3 in README on how to redirect and block by country 103 | - Fixed Garbage characters appearing in GeoIP Postal Code field, this 104 | bug was introduced in 1.1.3 105 | 106 | 1.1.6 2005-05-17 107 | 108 | - Fixed empty fields for GeoIP Region fields, this bug 109 | was introduced in 1.1.3 110 | 111 | 1.1.5 2005-04-19 112 | 113 | - Removed dependence on DNS resolver for GeoIP Region and Netspeed databases 114 | 115 | 1.1.4 2004-12-23 116 | 117 | - Fixed Garbage characters appearing in GeoIP City/Region field, this 118 | bug was introduced in 1.1.3 119 | 120 | 1.1.3 2004-12-09 121 | 122 | - Added support for GeoIPOutput 123 | - Changed command setup to AP_INIT_TAKE12 from AP_INIT_TAKE1 GeoIPDBFile (merv) 124 | - Memory Leak fix when using GeoIP Region database 125 | - Memory Leak fix when using GeoIP City database (Shane Nelson) 126 | 127 | 1.1.2 2004-08-12 128 | 129 | - Added support for GeoIP Netspeed Edition (Frank Mather) 130 | - Added support for GeoIP City setting GEOIP_DMA_CODE, GEOIP_AREA_CODE, GEOIP_LATITUDE, 131 | GEOIP_LONGITUDE, and GEOIP_POSTAL_CODE (Frank Mather) 132 | 133 | 1.1.1 2004-07-12 134 | 135 | - Added more documentation for using from PHP 136 | - Fixed compile errors and warnings 137 | 138 | 1.1.0 2004-04-19 139 | 140 | - Added support for GeoIP Region, City, ISP and Organization (Frank Mather) 141 | 142 | 1.0.6 2002-08-30 143 | 144 | - Added GeoIP_delete upon cleanup (Corris Randall) 145 | 146 | 1.0.5 2002-08-29 147 | 148 | - Initial Release (Corris Randall) 149 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Requirements 4 | 5 | Apache 2.0.40 or higher installed If using RPM, the httpd-devel package 6 | containing apxs may need to be installed [GeoIP 1.4.8 or higher 7 | installed](https://github.com/maxmind/geoip-api-c/releases). 8 | 9 | ## Building 10 | 11 | To build mod_geoip as a dynamically loadable module: 12 | 13 | ``` 14 | apxs -i -a -L/usr/local/lib -I/usr/local/include -lGeoIP -c mod_geoip.c 15 | ``` 16 | 17 | `-I/usr/local/include` is where the GeoIP.h header file is installed. 18 | `-L/usr/local/lib` is where the libGeoIP library is located. 19 | 20 | This will put the correct LoadModule statement. 21 | 22 | ## Configuration 23 | 24 | To enable the module, place 25 | 26 | ``` 27 | 28 | GeoIPEnable On 29 | 30 | ``` 31 | 32 | inside your httpd.conf file. The `` block is not required but is 33 | recommended. 34 | 35 | You can optionally specify the data file by using: 36 | 37 | ``` 38 | 39 | GeoIPEnable On 40 | GeoIPDBFile /usr/tmp/GeoIP.dat 41 | 42 | ``` 43 | 44 | 45 | See the README.md file for more details on the configuration 46 | 47 | ## Troubleshooting 48 | 49 | On RedHat 9, apxs places 50 | 51 | ``` 52 | LoadModule geoip_module /usr/lib/httpd/modules/mod_geoip.so 53 | ``` 54 | 55 | Inside a 56 | 57 | ``` 58 | 59 | 60 | ``` 61 | Block. 62 | 63 | If mod_geoip2 doesn't work, try taking the LoadModule geoip_module line outside 64 | the `` block. 65 | 66 | If you get the following errors: 67 | 68 | ``` 69 | parse error before "geoip_module" 70 | warning: data definition has no type or storage class 71 | ``` 72 | 73 | Or 74 | 75 | ``` 76 | syntax error before "geoip_module" 77 | ``` 78 | 79 | Make sure that the apxs script belongs to the Apache server you are using. 80 | These error messages result from using a Apache 1.3 apxs script with a Apache 81 | 2.x server. 82 | 83 | If you get a `libGeoIP.so.1: cannot open shared object file: No such file or 84 | directory` error, add `/usr/local/lib` to `/etc/ld.so.conf` then run 85 | `/sbin/ldconfig /etc/ld.so.conf` 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * The Apache Software License, Version 1.1 3 | * 4 | * Copyright (c) 2004 MaxMind, Inc. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * 3. The end-user documentation included with the redistribution, 19 | * if any, must include the following acknowledgment: 20 | * "This product includes software developed by the 21 | * Apache Software Foundation (http://www.apache.org/)." 22 | * Alternately, this acknowledgment may appear in the software itself, 23 | * if and wherever such third-party acknowledgments normally appear. 24 | * 25 | * 4. The names "Apache" and "Apache Software Foundation" must 26 | * not be used to endorse or promote products derived from this 27 | * software without prior written permission. For written 28 | * permission, please contact apache@apache.org. 29 | * 30 | * 5. Products derived from this software may not be called "Apache", 31 | * nor may "Apache" appear in their name, without prior written 32 | * permission of the Apache Software Foundation. 33 | * 34 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 35 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 37 | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 38 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 41 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 42 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 43 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 44 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 45 | * SUCH DAMAGE. 46 | * ==================================================================== 47 | */ 48 | 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GeoIP Legacy Apache Module 2 | ========================== 3 | 4 | End of Life 5 | ----------- 6 | 7 | MaxMind will be retiring the GeoIP Legacy databases at the end of May 8 | 2022. Until then, this library will only receive critical security and bug 9 | fixes. Support for this library will end completely with the last release of 10 | the legacy GeoIP databases. 11 | 12 | We recommend that you upgrade to our GeoIP2 databases. You can read these 13 | from Apache using [mod_maxminddb](https://github.com/maxmind/mod_maxminddb). 14 | 15 | See [our blog post](https://blog.maxmind.com/2020/06/01/retirement-of-geoip-legacy-downloadable-databases-in-may-2022/) 16 | for more information. 17 | 18 | Description 19 | ----------- 20 | 21 | The mod_geoip2 module embeds GeoIP Legacy database lookups into the 22 | Apache web server. It is only capable of looking up the IP of a client 23 | that connects to the web server, as opposed to looking up arbitrary 24 | addresses. 25 | 26 | This module works with Apache 2. Please use 27 | [mod_geoip](http://www.maxmind.com/download/geoip/api/mod_geoip/mod_geoip-latest.tar.gz) 28 | with Apache 1. 29 | 30 | IP Geolocation Usage 31 | -------------------- 32 | 33 | IP geolocation is inherently imprecise. Locations are often near the center of 34 | the population. Any location provided by a GeoIP database should not be used to 35 | identify a particular address or household. 36 | 37 | Version 38 | ------- 39 | 40 | The latest version of mod_geoip2 can be found on the [GitHub Releases 41 | page](https://github.com/maxmind/geoip-api-mod_geoip2/releases). 42 | 43 | Installation 44 | ------------ 45 | 46 | You can [download 47 | mod_geoip2](https://github.com/maxmind/geoip-api-mod_geoip2/releases) 48 | from GitHub or get the latest development version from 49 | [GitHub](https://github.com/maxmind/geoip-api-mod_geoip2). See the 50 | `INSTALL` file in the tarball for installation details. 51 | 52 | Overview 53 | -------- 54 | 55 | The mod_geoip2 module uses the libGeoIP library to look up geolocation 56 | information for a client as part of the http request process. This 57 | module is free software, and is licensed under the [Apache Software 58 | License, Version 1.1](http://www.apache.org/licenses/LICENSE-1.1). 59 | 60 | To compile and install this module, you must first install [libGeoIP 61 | 1.4.3](https://github.com/maxmind/geoip-api-c) or newer. 62 | 63 | The mod_geoip2 module takes effect either during request header parsing 64 | phase or the post read request phase, depending on whether it is 65 | configured for server-wide use or for a specific location/directory. 66 | 67 | When enabled, the module looks at the incoming IP address and sets some 68 | variables which provide geolocation information for that IP. The 69 | variables it set depend on the specific GeoIP Legacy database being used 70 | (Country, City, ISP, etc.). These variables can be set in either the 71 | request notes table, the environment or both depending on the server 72 | configuration. 73 | 74 | Configuration 75 | ------------- 76 | 77 | With the exception of `GeoIPEnable`, all GeoIP configuration directives 78 | must be placed in the server-wide context of the main server config. 79 | (Please see [Server vs Directory context](#Server_vs_Directory_context) 80 | for a full explanation). After installing the module, make sure that 81 | 82 | GeoIPEnable On 83 | 84 | is set in your Apache configuration file or an `.htaccess` file. This 85 | will call the GeoIP Legacy Country database from its default location 86 | (e.g. /usr/local/share/GeoIP/GeoIP.dat) 87 | 88 | If you want to specify options, for example to use a different database 89 | or to pass caching options, you can use the `GeoIPDBFile` directive: 90 | 91 | ### File and Caching Directives 92 | 93 | GeoIPDBFile /path/to/GeoIP.dat [GeoIPFlag] 94 | 95 | For example: 96 | 97 | GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache 98 | GeoIPDBFile /usr/local/share/GeoIP/GeoIPOrg.dat Standard 99 | 100 | The default GeoIPFlag value is Standard, which does not perform any 101 | caching, but uses the least memory. To turn on memory caching use: 102 | 103 | GeoIPDBFile /path/to/GeoIP.dat MemoryCache 104 | 105 | The memory cache option can use a large amount of memory. We recommend 106 | that you use Memory Caching only for the smaller database files, such as 107 | GeoIP Legacy Country and GeoIP Legacy ISP. 108 | 109 | Another MemoryCache option is MMapCache, which uses the the `mmap` 110 | system call to map the database file into memory. 111 | 112 | If you would like the API to check to see if your local GeoIP Legacy 113 | files have been updated, set the `CheckCache` flag: 114 | 115 | GeoIPDBFile /path/to/GeoIP.dat CheckCache 116 | 117 | Before making a call to the database, geoip will check the GeoIP.dat 118 | file to see if it has changed. If it has, then it will reload the file. 119 | With this option, you do not have to restart Apache when you update your 120 | GeoIP Legacy databases. 121 | 122 | If you would like to turn on partial memory caching, use the 123 | `IndexCache` flag: 124 | 125 | GeoIPDBFile /path/to/GeoIP.dat IndexCache 126 | 127 | The IndexCache option caches the most frequently accessed index portion 128 | of the database, resulting in faster lookups than StandardCache, but 129 | less memory usage than MemoryCache. This is especially useful for larger 130 | databases such as GeoIP Legacy Organization and GeoIP Legacy City. For 131 | the GeoIP Legacy Country, Region and Netspeed databases, setting the 132 | IndexCache option just causes the C API to use the MemoryCache. 133 | 134 | Currently, multiple GeoIPFlags options can not be combined. 135 | 136 | ### Enabling UTF-8 Output 137 | 138 | You may change the output charset from ISO-8859-1 (Latin-1) to UTF-8 139 | with this directive: 140 | 141 | GeoIPEnableUTF8 On 142 | 143 | By default mod_geoip2 sets variables in both the notes table and 144 | environment. For performance reasons you may want to set only the one 145 | you use. To do so, use the `GeoIPOutput` configuration directive: 146 | 147 | ### Output Variable Location 148 | 149 | GeoIPOutput Notes # Sets the Apache notes table only 150 | GeoIPOutput Env # Sets environment variables only 151 | GeoIPOutput Request # Sets input headers with the geo location information 152 | GeoIPOutput All # Sets all three (default behaviour) 153 | 154 | ### Proxy-Related Directives 155 | 156 | By default, this module will simply look at the IP address of the 157 | client. However, if the client is using a proxy, this will be the 158 | address of the proxy. You can use the `GeoIPScanProxyHeaders` directive 159 | to look at proxy-related headers. 160 | 161 | GeoIPScanProxyHeaders On 162 | 163 | When this is set, the module will look at several other sources for the 164 | IP address, in this order: 165 | 166 | - The `HTTP_CLIENT_IP` environment variable (set by Apache). 167 | - The `HTTP_X_FORWARDED_FOR` environment variable (set by Apache). 168 | - The `X-Forwarded-For` for header (set by a proxy). 169 | - The `HTTP_REMOTE_ADDR` environment variable (set by Apache). 170 | 171 | This module will use the first IP address it finds in one of these 172 | locations *instead* of the IP address the client connected from. 173 | 174 | Some of these variables may contain a comma-separate list of IP 175 | addresses (when a client goes through multiple proxies). In this case, 176 | the default behavior is to use the first IP address. You can set the 177 | `GeoIPUseLastXForwardedForIP` directive to use the last address instead: 178 | 179 | GeoIPUseLastXForwardedForIP On 180 | 181 | Or use `GeoIPUseFirstNonPrivateXForwardedForIP` to use the first non 182 | private IP Address. 183 | 184 | GeoIPUseFirstNonPrivateXForwardedForIP On 185 | 186 | Apache 2.4 users using mod_remoteip to pick the IP address of the user 187 | should disable GeoIPScanProxyHeaders. Mod_geoip2 will use whatever 188 | mod_remoteip provides. 189 | 190 | GeoIPScanProxyHeaderField FieldName 191 | 192 | Sometimes it is useful to use another field as the source for the 193 | client's IP address. You can set this directive to tell this module 194 | which header to look at in order to determine the client's IP address. 195 | 196 | Output Variables 197 | ---------------- 198 | 199 | As noted above, these variables can be set in either the Apache request 200 | notes table, the environment, or both. The specific variables which are 201 | set depend on the database you are using. 202 | 203 | ### GeoIP Country Edition Output Variables 204 | 205 | #### GEOIP_ADDR 206 | 207 | The address used to calculate the GeoIP output. 208 | 209 | #### GEOIP_CONTINENT_CODE 210 | 211 | A two-character code for the continent associated with the IP address. 212 | The possible codes are: 213 | 214 | - **AF** - Africa 215 | - **AS** - Asia 216 | - **EU** - Europe 217 | - **NA** - North America 218 | - **OC** - Oceania 219 | - **SA** - South America 220 | 221 | #### GEOIP_COUNTRY_CODE 222 | 223 | A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) 224 | country code for the country associated with the IP address. In addition 225 | to the standard codes, we may also return one of the following: 226 | 227 | - **A1** - an [anonymous 228 | proxy](https://dev.maxmind.com/faq/what-are-the-a1-anonymous-proxy-entries/). 229 | - **A2** - a [satellite 230 | provider](https://dev.maxmind.com/faq/what-are-the-a2-satellite-provider-entries/). 231 | - **EU** - an IP in a block used by multiple 232 | [European](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 233 | countries. 234 | - **AP** - an IP in a block used by multiple [Asia/Pacific 235 | region](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 236 | countries. 237 | 238 | The **US** country code is returned for IP addresses associated with 239 | overseas US military bases. 240 | 241 | #### GEOIP_COUNTRY_NAME 242 | 243 | The country name associated with the IP address. 244 | 245 | ### GeoIP Region Edition Output Variables 246 | 247 | #### GEOIP_ADDR 248 | 249 | The address used to calculate the GeoIP output. 250 | 251 | #### GEOIP_COUNTRY_CODE 252 | 253 | A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) 254 | country code for the country associated with the IP address. In addition 255 | to the standard codes, we may also return one of the following: 256 | 257 | - **A1** - an [anonymous 258 | proxy](https://dev.maxmind.com/faq/what-are-the-a1-anonymous-proxy-entries/). 259 | - **A2** - a [satellite 260 | provider](https://dev.maxmind.com/faq/what-are-the-a2-satellite-provider-entries/). 261 | - **EU** - an IP in a block used by multiple 262 | [European](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 263 | countries. 264 | - **AP** - an IP in a block used by multiple [Asia/Pacific 265 | region](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 266 | countries. 267 | 268 | The **US** country code is returned for IP addresses associated with 269 | overseas US military bases. 270 | 271 | #### GEOIP_REGION_NAME 272 | 273 | The region name associated with the IP address. 274 | 275 | #### GEOIP_REGION 276 | 277 | A two character [ISO-3166-2](http://en.wikipedia.org/wiki/ISO_3166-2) or 278 | [FIPS 10-4](http://en.wikipedia.org/wiki/FIPS_10-4) code for the 279 | state/region associated with the IP address. 280 | 281 | For the US and Canada, we return an ISO-3166-2 code. In addition to the 282 | standard ISO codes, we may also return one of the following: 283 | 284 | - **AA** - Armed Forces America 285 | - **AE** - Armed Forces Europe 286 | - **AP** - Armed Forces Pacific 287 | 288 | We return a FIPS code for all other countries. 289 | 290 | We provide a [CSV file which maps our region codes to region 291 | names](http://www.maxmind.com/download/geoip/misc/region_codes.csv). The 292 | columns are ISO country code, region code (FIPS or ISO), and the region 293 | name. 294 | 295 | ### GeoIP City Edition Output Variables 296 | 297 | #### GEOIP_ADDR 298 | 299 | The address used to calculate the GeoIP output. 300 | 301 | #### GEOIP_CONTINENT_CODE 302 | 303 | A two-character code for the continent associated with the IP address. 304 | The possible codes are: 305 | 306 | - **AF** - Africa 307 | - **AS** - Asia 308 | - **EU** - Europe 309 | - **NA** - North America 310 | - **OC** - Oceania 311 | - **SA** - South America 312 | 313 | #### GEOIP_COUNTRY_CODE 314 | 315 | A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) 316 | country code for the country associated with the IP address. In addition 317 | to the standard codes, we may also return one of the following: 318 | 319 | - **A1** - an [anonymous 320 | proxy](https://dev.maxmind.com/faq/what-are-the-a1-anonymous-proxy-entries/). 321 | - **A2** - a [satellite 322 | provider](https://dev.maxmind.com/faq/what-are-the-a2-satellite-provider-entries/). 323 | - **EU** - an IP in a block used by multiple 324 | [European](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 325 | countries. 326 | - **AP** - an IP in a block used by multiple [Asia/Pacific 327 | region](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 328 | countries. 329 | 330 | The **US** country code is returned for IP addresses associated with 331 | overseas US military bases. 332 | 333 | #### GEOIP_REGION 334 | 335 | A two character [ISO-3166-2](http://en.wikipedia.org/wiki/ISO_3166-2) or 336 | [FIPS 10-4](http://en.wikipedia.org/wiki/FIPS_10-4) code for the 337 | state/region associated with the IP address. 338 | 339 | For the US and Canada, we return an ISO-3166-2 code. In addition to the 340 | standard ISO codes, we may also return one of the following: 341 | 342 | - **AA** - Armed Forces America 343 | - **AE** - Armed Forces Europe 344 | - **AP** - Armed Forces Pacific 345 | 346 | We return a FIPS code for all other countries. 347 | 348 | We provide a [CSV file which maps our region codes to region 349 | names](http://www.maxmind.com/download/geoip/misc/region_codes.csv). The 350 | columns are ISO country code, region code (FIPS or ISO), and the region 351 | name. 352 | 353 | #### GEOIP_REGION_NAME 354 | 355 | The region name associated with the IP address. 356 | 357 | #### GEOIP_CITY 358 | 359 | The city or town name associated with the IP address. See our [list of 360 | cities](http://www.maxmind.com/GeoIPCity-534-Location.csv) to see all 361 | the possible return values. This list is updated on a regular basis. 362 | 363 | #### GEOIP_METRO_CODE 364 | 365 | The metro code associated with the IP address. These are only available 366 | for IP addresses in the US. MaxMind returns the [same metro codes as the 367 | Google AdWords 368 | API](https://developers.google.com/adwords/api/docs/appendix/cities-DMAregions). 369 | 370 | #### GEOIP_AREA_CODE 371 | 372 | The telephone area code associated with the IP address. These are only 373 | available for IP addresses in the US. 374 | 375 | #### GEOIP_LATITUDE 376 | 377 | The approximate latitude of the location associated with the IP address. This 378 | value is not precise and should not be used to identify a particular address 379 | or household. 380 | 381 | #### GEOIP_LONGITUDE 382 | 383 | The approximate longitude of the location associated with the IP address. This 384 | value is not precise and should not be used to identify a particular address 385 | or household. 386 | 387 | #### GEOIP_POSTAL_CODE 388 | 389 | The postal code associated with the IP address. These are available for 390 | some IP addresses in the US, Canada, Germany, and United Kingdom. 391 | 392 | ### GeoIP ISP Edition Output Variables 393 | 394 | #### GEOIP_ADDR 395 | 396 | The address used to calculate the GeoIP output. 397 | 398 | #### GEOIP_ISP 399 | 400 | The name of the ISP associated with the IP address. 401 | 402 | ### GeoIP Organization Edition Output Variables 403 | 404 | #### GEOIP_ADDR 405 | 406 | The address used to calculate the GeoIP output. 407 | 408 | #### GEOIP_ORGANIZATION 409 | 410 | The name of the organization associated with the IP address. 411 | 412 | ### GeoIP Netspeed Edition Output Variables 413 | 414 | #### GEOIP_ADDR 415 | 416 | The address used to calculate the GeoIP output. 417 | 418 | #### GEOIP_NETSPEED 419 | 420 | The network speed associated with the IP address. This can be one of the 421 | following values: 422 | 423 | - **Dialup** 424 | - **Cable/DSL** 425 | - **Corporate** 426 | - **Cellular** 427 | 428 | ### GeoIPv6 Edition (experimental) Output Variables 429 | 430 | #### GEOIP_ADDR 431 | 432 | The address used to calculate the GeoIP output. 433 | 434 | #### GEOIP_CONTINENT_CODE_V6 435 | 436 | A two-character code for the continent associated with the IP address. 437 | The possible codes are: 438 | 439 | - **AF** - Africa 440 | - **AS** - Asia 441 | - **EU** - Europe 442 | - **NA** - North America 443 | - **OC** - Oceania 444 | - **SA** - South America 445 | 446 | #### GEOIP_COUNTRY_CODE_V6 447 | 448 | A two-character [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) 449 | country code for the country associated with the IP address. In addition 450 | to the standard codes, we may also return one of the following: 451 | 452 | - **A1** - an [anonymous 453 | proxy](https://dev.maxmind.com/faq/what-are-the-a1-anonymous-proxy-entries/). 454 | - **A2** - a [satellite 455 | provider](https://dev.maxmind.com/faq/what-are-the-a2-satellite-provider-entries/). 456 | - **EU** - an IP in a block used by multiple 457 | [European](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 458 | countries. 459 | - **AP** - an IP in a block used by multiple [Asia/Pacific 460 | region](https://dev.maxmind.com/faq/what-are-the-eu-europe-and-ap-asia-pacific-entries/) 461 | countries. 462 | 463 | The **US** country code is returned for IP addresses associated with 464 | overseas US military bases. 465 | 466 | #### GEOIP_COUNTRY_NAME_V6 467 | 468 | The country name associated with the IP address. 469 | 470 | Examples 471 | -------- 472 | 473 | Here are some examples of how you can use mod_geoip2. 474 | 475 | ### Redirecting a client based on country 476 | 477 | This example show you how to redirect a client based on the country code 478 | that GeoIP sets. 479 | 480 | GeoIPEnable On 481 | GeoIPDBFile /path/to/GeoIP.dat 482 | 483 | # Redirect one country 484 | RewriteEngine on 485 | RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^CA$ 486 | RewriteRule ^(.*)$ http://www.canada.com$1 [R,L] 487 | 488 | # Redirect multiple countries to a single page 489 | RewriteEngine on 490 | RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^(CA|US|MX)$ 491 | RewriteRule ^(.*)$ http://www.northamerica.com$1 [R,L] 492 | 493 | ### Blocking a client based on country 494 | 495 | This example show you how to block clients based on the country code 496 | that GeoIP sets. 497 | 498 | GeoIPEnable On 499 | GeoIPDBFile /path/to/GeoIP.dat 500 | 501 | SetEnvIf GEOIP_COUNTRY_CODE CN BlockCountry 502 | SetEnvIf GEOIP_COUNTRY_CODE RU BlockCountry 503 | # ... place more countries here 504 | 505 | Deny from env=BlockCountry 506 | 507 | ### Allowing clients based on country 508 | 509 | This example show you how to allow only clients from specific countries. 510 | 511 | GeoIPEnable On 512 | GeoIPDBFile /path/to/GeoIP.dat 513 | 514 | SetEnvIf GEOIP_COUNTRY_CODE US AllowCountry 515 | SetEnvIf GEOIP_COUNTRY_CODE CA AllowCountry 516 | SetEnvIf GEOIP_COUNTRY_CODE MX AllowCountry 517 | # ... place more countries here 518 | 519 | Deny from all 520 | Allow from env=AllowCountry 521 | 522 | ### Server vs Directory context 523 | 524 | All directives except GeoIPEnable are server config only, i.e., you type 525 | it only once per server config. Otherwise the latest wins. 526 | 527 | ``` {.lang:default .decode:true} 528 | 529 | GeoIPEnable Off 530 | GeoIPEnableUTF8 On 531 | GeoIPOutput Env 532 | GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache 533 | GeoIPDBFile /usr/local/share/GeoIP/GeoIPCity.dat MemoryCache 534 | GeoIPDBFile /usr/local/share/GeoIP/GeoIPOrg.dat MemoryCache 535 | 536 | ``` 537 | 538 | GeoIPEnable is useful in server or directory context. For example: 539 | 540 | GeoIP is only available for a specific location: 541 | 542 | ``` {.lang:default .decode:true} 543 | 544 | GeoIPEnable Off 545 | GeoIPEnableUTF8 On 546 | GeoIPOutput Env 547 | GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache 548 | 549 | 550 | # GeoIP information is avail only inside /xxx 551 | 552 | GeoIPEnable On 553 | ... 554 | 555 | 556 | 557 | ... 558 | 559 | ``` 560 | 561 | GeoIP is available for all locations: 562 | 563 | ``` {.lang:default .decode:true} 564 | 565 | GeoIPEnable On 566 | GeoIPEnableUTF8 On 567 | GeoIPOutput Env 568 | GeoIPDBFile /usr/local/share/GeoIP/GeoIP.dat MemoryCache 569 | 570 | 571 | # This doesn't work, because it's already been enabled in the server-wide 572 | # config! 573 | 574 | GeoIPEnable On 575 | 576 | 577 | 578 | GeoIPEnable Off 579 | 580 | ``` 581 | 582 | Memory Usage 583 | ------------ 584 | 585 | Starting with mod_geoip2 version 1.2.1, all Apache child processes 586 | share the same database when you set the MemoryCache or MMapCache flag. 587 | 588 | Memory usage is about the same as the database file size, no matter how 589 | many child processes Apache spawns. The only thing to remember is ask 590 | Apache to update if your database changes. Use the graceful restart 591 | option to do so without stopping Apache. 592 | 593 | Performance 594 | ----------- 595 | 596 | For improved performance, you may want to enable mod_geoip only for 597 | specific HTML pages. If you want to use the mod_geoip module site-wide, 598 | you may still be able to only use it for HTML pages and not images. To 599 | restrict the pages where mod_geoip2 is used, place the `GeoIPEnable On` 600 | directive inside a , or directive, see: 601 | [httpd.apache.org/docs/2.0/sections.html](http://httpd.apache.org/docs/2.0/sections.html) 602 | 603 | Troubleshooting 604 | --------------- 605 | 606 | If the module is not working, make sure that the httpd user (e.g. 607 | nobody) has read access to the GeoIP database file(s) you are using. 608 | 609 | If the GeoIP variables do not show up please make sure that the client 610 | IP address is not on a private network such as 10.0.0.0/8, 172.16.0.0/12 611 | or 192.168.0.0/16. GeoIP can only look up public IP addresses. 612 | 613 | ------ 614 | 615 | This file was generated by running 616 | 617 | pandoc --from html --to markdown 618 | 619 | Using the pre-generated HTML from 620 | http://dev.maxmind.com/geoip/legacy/mod_geoip2 as the input. 621 | -------------------------------------------------------------------------------- /README.php: -------------------------------------------------------------------------------- 1 | To use from PHP, use something like: 2 | 3 | GeoIP Country: 4 | 8 | 9 | GeoIP Region: 10 | 14 | 15 | GeoIP City: 16 | 21 | 22 | ================================================== 23 | Redirection with PHP 24 | 25 | $country_code = apache_note("GEOIP_COUNTRY_CODE"); 26 | if ( $country_code == "DE" ) 27 | { 28 | header ("Location: http://www.google.de" ); 29 | } 30 | else 31 | { 32 | header ("Location: http://www.yoursite.com" ); 33 | } 34 | -------------------------------------------------------------------------------- /mod_geoip.c: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * The Apache Software License, Version 1.1 3 | * 4 | * Copyright (c) 2004 MaxMind, Inc. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * 3. The end-user documentation included with the redistribution, 19 | * if any, must include the following acknowledgment: 20 | * "This product includes software developed by the 21 | * MaxMind (http://www.maxmind.com/)." 22 | * Alternately, this acknowledgment may appear in the software itself, 23 | * if and wherever such third-party acknowledgments normally appear. 24 | * 25 | * 4. The names "MaxMind" and "GeoIP" must 26 | * not be used to endorse or promote products derived from this 27 | * software without prior written permission. For written 28 | * permission, please contact support@maxmind.com. 29 | * 30 | * 5. Products derived from this software may not be called "GeoIP", 31 | * nor may "MaxMind" appear in their name, without prior written 32 | * permission of the MaxMind. 33 | * 34 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 35 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 37 | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 38 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 41 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 42 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 43 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 44 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 45 | * SUCH DAMAGE. 46 | * ==================================================================== 47 | * 48 | */ 49 | 50 | /* This module sets an environment variable to the remote country 51 | * based on the requester's IP address. It uses the GeoIP library 52 | * to lookup the country by IP address. 53 | */ 54 | 55 | #include "httpd.h" 56 | #include "http_config.h" 57 | #include "http_protocol.h" 58 | #include "http_log.h" 59 | #include "ap_config.h" 60 | #include "apr_strings.h" 61 | #include "util_script.h" 62 | #include 63 | #include "GeoIP.h" 64 | #include "GeoIPCity.h" 65 | 66 | typedef struct { 67 | int GeoIPEnabled; 68 | } geoip_dir_config_rec; 69 | 70 | typedef struct { 71 | GeoIP **gips; 72 | int numGeoIPFiles; 73 | char **GeoIPFilenames; 74 | int GeoIPEnabled; 75 | int GeoIPEnableUTF8; 76 | char GeoIPOutput; 77 | int GeoIPFlags; 78 | int *GeoIPFlags2; 79 | int scanProxyHeaders; 80 | int proxyHeaderMode; 81 | char *GeoIPProxyField; 82 | } geoip_server_config_rec; 83 | 84 | static const int GEOIP_PROXY_HEADER_MODE_FIRST_IP = 0; 85 | static const int GEOIP_PROXY_HEADER_MODE_LAST_IP = 1; 86 | static const int GEOIP_PROXY_HEADER_MODE_FIRST_NON_PRIVATE_IP = 2; 87 | static const int GEOIP_PROXY_HEADER_MODE_DEFAULT = 0; 88 | 89 | static const int GEOIP_NONE = 0; 90 | static const int GEOIP_DEFAULT = 1; 91 | static const int GEOIP_NOTES = 2; 92 | static const int GEOIP_ENV = 4; 93 | static const int GEOIP_REQUEST = 8; 94 | static const int GEOIP_ALL = 14; 95 | static const int GEOIP_INIT = 15; 96 | 97 | static const int GEOIP_UNKNOWN = -1; 98 | 99 | char metrocodestr[100]; 100 | char areacodestr[100]; 101 | char latstr[100]; 102 | char lonstr[100]; 103 | const char *netspeedstring; 104 | 105 | module AP_MODULE_DECLARE_DATA geoip_module; 106 | 107 | uint32_t _private_ipv4_networks[] = { 108 | 167772160U, 184549375U, // 10.0.0.0/8 109 | 1681915904U, 1686110207U, // 100.64.0.0/10 110 | 2130706432U, 2147483647U, // 127.0.0.0/8 111 | 2886729728U, 2887778303U, // 172.16.0.0/12 112 | 3221225984U, 3221226239U, // 192.0.2.0/24 113 | 3227017984U, 3227018239U, // 192.88.99.0/24 114 | 3232235520U, 3232301055U, // 192.168.0.0/16 115 | 2851995648U, 2852061183U, // 169.254.0.0/16 116 | 0U, 0U 117 | }; 118 | 119 | static int _is_private(uint32_t ipnum) 120 | { 121 | uint32_t min, max; 122 | uint32_t *p = _private_ipv4_networks; 123 | while ((min = *p++)) { 124 | max = *p++; 125 | if (ipnum < min || ipnum > max) { 126 | continue; 127 | } 128 | return 1; 129 | } 130 | return 0; 131 | } 132 | 133 | char *_get_ip_from_xff(request_rec *r, const char *xffheader) 134 | { 135 | char *xff = apr_pstrdup(r->pool, xffheader); 136 | char *xff_ip, *break_ptr; 137 | uint32_t ipnum; 138 | if (xff) { 139 | for (xff_ip = strtok_r(xff, " \t,", &break_ptr); xff_ip; 140 | xff_ip = strtok_r(NULL, " \t,", &break_ptr)) { 141 | if (1 != inet_pton(AF_INET, xff_ip, &ipnum)) { 142 | continue; 143 | } 144 | ipnum = htonl(ipnum); 145 | if (!_is_private(ipnum)) { 146 | char *found = apr_pstrdup(r->pool, xff_ip); 147 | return found; 148 | } 149 | } 150 | } 151 | return NULL; 152 | } 153 | 154 | /* create a disabled directory entry */ 155 | 156 | static void *geoip_create_dir_config(apr_pool_t * p, char *d) 157 | { 158 | 159 | geoip_dir_config_rec *dcfg; 160 | 161 | dcfg = 162 | (geoip_dir_config_rec *)apr_pcalloc(p, sizeof(geoip_dir_config_rec)); 163 | dcfg->GeoIPEnabled = 0; 164 | 165 | return dcfg; 166 | } 167 | 168 | static apr_status_t geoip_cleanup(void *cfgdata) 169 | { 170 | int i; 171 | geoip_server_config_rec *cfg = (geoip_server_config_rec *)cfgdata; 172 | if (cfg->gips) { 173 | for (i = 0; i < cfg->numGeoIPFiles; i++) { 174 | if (cfg->gips[i]) { 175 | GeoIP_delete(cfg->gips[i]); 176 | cfg->gips[i] = NULL; 177 | } 178 | } 179 | } 180 | return APR_SUCCESS; 181 | } 182 | 183 | /* initialize geoip any server ( any virtual server! ) */ 184 | static void geoip_server_init(apr_pool_t * p, server_rec * s) 185 | { 186 | geoip_server_config_rec *cfg; 187 | int i; 188 | 189 | while (s) { 190 | cfg = (geoip_server_config_rec *) 191 | ap_get_module_config(s->module_config, &geoip_module); 192 | 193 | if (!cfg->gips) { 194 | if (cfg->GeoIPFilenames != NULL) { 195 | cfg->gips = apr_pcalloc(p, sizeof(GeoIP *) * cfg->numGeoIPFiles); 196 | for (i = 0; i < cfg->numGeoIPFiles; i++) { 197 | cfg->gips[i] = 198 | GeoIP_open(cfg->GeoIPFilenames[i], 199 | (cfg->GeoIPFlags2[i] == 200 | GEOIP_UNKNOWN) ? cfg->GeoIPFlags 201 | : cfg->GeoIPFlags2[i]); 202 | 203 | if (cfg->gips[i]) { 204 | if (cfg->GeoIPEnableUTF8) { 205 | GeoIP_set_charset(cfg->gips[i], GEOIP_CHARSET_UTF8); 206 | } 207 | } else { 208 | ap_log_error( 209 | APLOG_MARK, APLOG_ERR, 0, 210 | s, 211 | "[mod_geoip]: Error while opening data file %s", 212 | cfg->GeoIPFilenames[i]); 213 | continue; 214 | } 215 | } 216 | } else { 217 | cfg->gips = apr_pcalloc(p, sizeof(GeoIP *)); 218 | cfg->gips[0] = GeoIP_new(GEOIP_STANDARD); 219 | if (!cfg->gips[0]) { 220 | ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 221 | "[mod_geoip]: Error while opening data file"); 222 | } 223 | cfg->numGeoIPFiles = 1; 224 | } 225 | apr_pool_cleanup_register(p, (void *)cfg, geoip_cleanup, 226 | geoip_cleanup); 227 | } 228 | 229 | s = s->next; 230 | } 231 | } 232 | 233 | static void geoip_child_init(apr_pool_t * p, server_rec * s) 234 | { 235 | geoip_server_config_rec *cfg; 236 | int i, flags; 237 | 238 | while (s) { 239 | cfg = (geoip_server_config_rec *) 240 | ap_get_module_config(s->module_config, &geoip_module); 241 | 242 | if (cfg->gips) { 243 | if (cfg->GeoIPFilenames != NULL) { 244 | for (i = 0; i < cfg->numGeoIPFiles; i++) { 245 | flags = 246 | (cfg->GeoIPFlags2[i] == 247 | GEOIP_UNKNOWN) ? cfg->GeoIPFlags : cfg->GeoIPFlags2[i]; 248 | if (cfg->gips[i]) { 249 | GeoIP_delete(cfg->gips[i]); 250 | } 251 | cfg->gips[i] = GeoIP_open(cfg->GeoIPFilenames[i], flags); 252 | 253 | if (cfg->gips[i]) { 254 | if (cfg->GeoIPEnableUTF8) { 255 | GeoIP_set_charset(cfg->gips[i], GEOIP_CHARSET_UTF8); 256 | } 257 | } else { 258 | ap_log_error( 259 | APLOG_MARK, APLOG_ERR, 0, 260 | s, 261 | "[mod_geoip]: Error while opening data file %s", 262 | cfg->GeoIPFilenames[i]); 263 | continue; 264 | } 265 | } 266 | } else { 267 | if (cfg->gips[0]) { 268 | GeoIP_delete(cfg->gips[0]); 269 | } 270 | cfg->gips[0] = GeoIP_new(GEOIP_STANDARD); 271 | if (!cfg->gips[0]) { 272 | ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, 273 | "[mod_geoip]: Error while opening data file"); 274 | } 275 | cfg->numGeoIPFiles = 1; 276 | } 277 | apr_pool_cleanup_register(p, (void *)cfg, geoip_cleanup, 278 | geoip_cleanup); 279 | } 280 | 281 | s = s->next; 282 | } 283 | 284 | } 285 | 286 | /* map into the first apache */ 287 | static int 288 | geoip_post_config(apr_pool_t * p, apr_pool_t * plog, 289 | apr_pool_t * ptemp, server_rec * s) 290 | { 291 | 292 | geoip_server_init(p, s); 293 | return OK; 294 | } 295 | 296 | static int geoip_header_parser(request_rec * r); 297 | 298 | static int geoip_post_read_request(request_rec * r) 299 | { 300 | geoip_server_config_rec *cfg; 301 | cfg = ap_get_module_config(r->server->module_config, &geoip_module); 302 | 303 | if (!cfg) { 304 | return DECLINED; 305 | } 306 | 307 | if (!cfg->GeoIPEnabled) { 308 | return DECLINED; 309 | } 310 | 311 | return geoip_header_parser(r); 312 | } 313 | 314 | static int geoip_per_dir(request_rec * r) 315 | { 316 | 317 | geoip_dir_config_rec *dcfg; 318 | 319 | geoip_server_config_rec *cfg = 320 | ap_get_module_config(r->server->module_config, &geoip_module); 321 | if (cfg && cfg->GeoIPEnabled) { 322 | return DECLINED; 323 | } 324 | 325 | dcfg = ap_get_module_config(r->per_dir_config, &geoip_module); 326 | if (!dcfg) { 327 | return DECLINED; 328 | } 329 | 330 | if (!dcfg->GeoIPEnabled) { 331 | return DECLINED; 332 | } 333 | 334 | return geoip_header_parser(r); 335 | } 336 | 337 | char *_get_client_ip(request_rec * r) 338 | { 339 | # if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER == 4 340 | return r->useragent_ip; 341 | # else 342 | return r->connection->remote_ip; 343 | #endif 344 | } 345 | 346 | static void geoip_say(geoip_server_config_rec * cfg, request_rec * r, 347 | const char *key, const char *value) 348 | { 349 | if (value) { 350 | if (cfg->GeoIPOutput & GEOIP_NOTES) { 351 | apr_table_set(r->notes, key, value); 352 | } 353 | if (cfg->GeoIPOutput & GEOIP_ENV) { 354 | apr_table_set(r->subprocess_env, key, value); 355 | } 356 | if (cfg->GeoIPOutput & GEOIP_REQUEST) { 357 | apr_table_set(r->headers_in, key, value); 358 | } 359 | } 360 | } 361 | 362 | static int geoip_header_parser(request_rec * r) 363 | { 364 | char *orgorisp; 365 | char *ipaddr; 366 | short int country_id; 367 | const char *continent_code; 368 | const char *country_code; 369 | const char *country_name; 370 | const char *region_name = NULL; 371 | 372 | geoip_server_config_rec *cfg; 373 | 374 | unsigned char databaseType; 375 | GeoIPRecord *gir; 376 | GeoIPRegion *giregion; 377 | int i; 378 | int netspeed; 379 | /* For splitting proxy headers */ 380 | char *ipaddr_ptr = NULL; 381 | char *comma_ptr; 382 | cfg = ap_get_module_config(r->server->module_config, &geoip_module); 383 | 384 | if (!cfg) { 385 | return DECLINED; 386 | } 387 | 388 | if (!cfg->scanProxyHeaders) { 389 | ipaddr = _get_client_ip(r); 390 | } else { 391 | ap_add_common_vars(r); 392 | if (cfg->GeoIPProxyField) { 393 | ipaddr_ptr = 394 | (char *)apr_table_get(r->headers_in, cfg->GeoIPProxyField); 395 | } else if (apr_table_get(r->subprocess_env, "HTTP_CLIENT_IP")) { 396 | ipaddr_ptr = 397 | (char *)apr_table_get(r->subprocess_env, "HTTP_CLIENT_IP"); 398 | } else if (apr_table_get(r->subprocess_env, "HTTP_X_FORWARDED_FOR")) { 399 | ipaddr_ptr = 400 | (char *)apr_table_get(r->subprocess_env, 401 | "HTTP_X_FORWARDED_FOR"); 402 | } else if (apr_table_get(r->headers_in, "X-Forwarded-For")) { 403 | ipaddr_ptr = 404 | (char *)apr_table_get(r->headers_in, "X-Forwarded-For"); 405 | } else if (apr_table_get(r->subprocess_env, "HTTP_REMOTE_ADDR")) { 406 | ipaddr_ptr = 407 | (char *)apr_table_get(r->subprocess_env, "HTTP_REMOTE_ADDR"); 408 | } 409 | if (!ipaddr_ptr) { 410 | ap_log_error( 411 | APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, 412 | r->server, 413 | "[mod_geoip]: Error while getting ipaddr from proxy headers. Using REMOTE_ADDR."); 414 | ipaddr = _get_client_ip(r); 415 | } else { 416 | /* Found XFF like header */ 417 | ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, 418 | r->server, "[mod_geoip]: IPADDR_PTR: %s", ipaddr_ptr); 419 | 420 | if (cfg->proxyHeaderMode == 421 | GEOIP_PROXY_HEADER_MODE_FIRST_NON_PRIVATE_IP) { 422 | ipaddr = _get_ip_from_xff(r, ipaddr_ptr); 423 | if (!ipaddr) { 424 | ipaddr = _get_client_ip(r); 425 | } 426 | } else { 427 | ipaddr = (char *)apr_pcalloc(r->pool, 8 * 4 + 7 + 1); 428 | /* proxyHeaderMode is 429 | * GEOIP_PROXY_HEADER_MODE_LAST_IP or GEOIP_PROXY_HEADER_MODE_FIRST_IP 430 | */ 431 | 432 | /* 433 | * Check to ensure that the HTTP_CLIENT_IP or 434 | * X-Forwarded-For header is not a comma separated 435 | * list of addresses, which would cause mod_geoip to 436 | * return no country code. If the header is a comma 437 | * separated list, return the first IP address in the 438 | * list, which is (hopefully!) the real client IP. 439 | */ 440 | 441 | if (cfg->proxyHeaderMode == GEOIP_PROXY_HEADER_MODE_LAST_IP) { 442 | comma_ptr = strrchr(ipaddr_ptr, ','); 443 | if (comma_ptr) { 444 | /* skip over whitespace */ 445 | ipaddr_ptr = comma_ptr + strspn(comma_ptr, ", \t"); 446 | } 447 | } 448 | 449 | strncpy(ipaddr, ipaddr_ptr, 8 * 4 + 7); 450 | comma_ptr = strchr(ipaddr, ','); 451 | if (comma_ptr != 0) { 452 | *comma_ptr = '\0'; 453 | } 454 | } 455 | } 456 | } 457 | 458 | geoip_say(cfg, r, "GEOIP_ADDR", ipaddr); 459 | 460 | for (i = 0; i < cfg->numGeoIPFiles; i++) { 461 | 462 | /* 463 | * skip database handles that can not be opned for some 464 | * reason 465 | */ 466 | if (cfg->gips[i] == NULL) { 467 | continue; 468 | } 469 | 470 | databaseType = cfg->gips[i] ? GeoIP_database_edition(cfg->gips[i]) : -1; /* -1 is "magic value" 471 | * in case file not 472 | * found */ 473 | switch (databaseType) { 474 | case GEOIP_NETSPEED_EDITION_REV1: 475 | orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); 476 | geoip_say(cfg, r, "GEOIP_NETSPEED", orgorisp); 477 | free(orgorisp); 478 | break; 479 | 480 | case GEOIP_NETSPEED_EDITION: 481 | netspeed = GeoIP_id_by_addr(cfg->gips[i], ipaddr); 482 | if (netspeed == GEOIP_UNKNOWN_SPEED) { 483 | netspeedstring = "unknown"; 484 | } else if (netspeed == GEOIP_DIALUP_SPEED) { 485 | netspeedstring = "dialup"; 486 | } else if (netspeed == GEOIP_CABLEDSL_SPEED) { 487 | netspeedstring = "cabledsl"; 488 | } else if (netspeed == GEOIP_CORPORATE_SPEED) { 489 | netspeedstring = "corporate"; 490 | } 491 | geoip_say(cfg, r, "GEOIP_NETSPEED", netspeedstring); 492 | break; 493 | case GEOIP_COUNTRY_EDITION_V6: 494 | /* Get the Country ID */ 495 | country_id = GeoIP_id_by_addr_v6(cfg->gips[i], ipaddr); 496 | 497 | if (country_id > 0) { 498 | /* Lookup the Code and the Name with the ID */ 499 | continent_code = GeoIP_country_continent[country_id]; 500 | country_code = GeoIP_country_code[country_id]; 501 | country_name = GeoIP_country_name[country_id]; 502 | 503 | if (cfg->numGeoIPFiles == 0) { 504 | cfg->numGeoIPFiles = 0; 505 | } 506 | if (cfg->GeoIPFilenames == 0) { 507 | cfg->GeoIPFilenames = 0; 508 | } 509 | /* Set it for our user */ 510 | geoip_say(cfg, r, "GEOIP_CONTINENT_CODE_V6", continent_code); 511 | geoip_say(cfg, r, "GEOIP_COUNTRY_CODE_V6", country_code); 512 | geoip_say(cfg, r, "GEOIP_COUNTRY_NAME_V6", country_name); 513 | } 514 | break; 515 | case GEOIP_COUNTRY_EDITION: 516 | /* Get the Country ID */ 517 | country_id = GeoIP_country_id_by_addr(cfg->gips[i], ipaddr); 518 | 519 | if (country_id > 0) { 520 | /* Lookup the Code and the Name with the ID */ 521 | continent_code = GeoIP_country_continent[country_id]; 522 | country_code = GeoIP_country_code[country_id]; 523 | country_name = GeoIP_country_name[country_id]; 524 | 525 | if (cfg->numGeoIPFiles == 0) { 526 | cfg->numGeoIPFiles = 0; 527 | } 528 | if (cfg->GeoIPFilenames == 0) { 529 | cfg->GeoIPFilenames = 0; 530 | } 531 | /* Set it for our user */ 532 | geoip_say(cfg, r, "GEOIP_CONTINENT_CODE", continent_code); 533 | geoip_say(cfg, r, "GEOIP_COUNTRY_CODE", country_code); 534 | geoip_say(cfg, r, "GEOIP_COUNTRY_NAME", country_name); 535 | } 536 | 537 | break; 538 | case GEOIP_REGION_EDITION_REV0: 539 | case GEOIP_REGION_EDITION_REV1: 540 | giregion = GeoIP_region_by_name(cfg->gips[i], ipaddr); 541 | if (giregion != NULL) { 542 | if (giregion->country_code[0]) { 543 | region_name = 544 | GeoIP_region_name_by_code 545 | (giregion->country_code, giregion->region); 546 | geoip_say(cfg, r, "GEOIP_COUNTRY_CODE", 547 | giregion->country_code); 548 | country_id = GeoIP_id_by_code(giregion->country_code); 549 | geoip_say(cfg, r, "GEOIP_COUNTRY_NAME", 550 | GeoIP_country_name[country_id]); 551 | geoip_say(cfg, r, "GEOIP_CONTINENT_CODE", 552 | GeoIP_country_continent[country_id]); 553 | } 554 | if (giregion->region[0]) { 555 | geoip_say(cfg, r, "GEOIP_REGION", giregion->region); 556 | } 557 | if (region_name != NULL) { 558 | geoip_say(cfg, r, "GEOIP_REGION_NAME", region_name); 559 | } 560 | GeoIPRegion_delete(giregion); 561 | } 562 | break; 563 | case GEOIP_CITY_EDITION_REV0_V6: 564 | case GEOIP_CITY_EDITION_REV1_V6: 565 | gir = GeoIP_record_by_addr_v6(cfg->gips[i], ipaddr); 566 | if (gir != NULL) { 567 | if (gir->country_code != NULL) { 568 | region_name = 569 | GeoIP_region_name_by_code(gir->country_code, 570 | gir->region); 571 | } 572 | sprintf(metrocodestr, "%d", gir->dma_code); 573 | sprintf(areacodestr, "%d", gir->area_code); 574 | geoip_say(cfg, r, "GEOIP_CONTINENT_CODE_V6", 575 | gir->continent_code); 576 | geoip_say(cfg, r, "GEOIP_COUNTRY_CODE_V6", gir->country_code); 577 | geoip_say(cfg, r, "GEOIP_COUNTRY_NAME_V6", gir->country_name); 578 | geoip_say(cfg, r, "GEOIP_REGION_V6", gir->region); 579 | geoip_say(cfg, r, "GEOIP_REGION_NAME_V6", region_name); 580 | geoip_say(cfg, r, "GEOIP_CITY_V6", gir->city); 581 | geoip_say(cfg, r, "GEOIP_DMA_CODE_V6", metrocodestr); 582 | geoip_say(cfg, r, "GEOIP_METRO_CODE_V6", metrocodestr); 583 | geoip_say(cfg, r, "GEOIP_AREA_CODE_V6", areacodestr); 584 | sprintf(latstr, "%f", gir->latitude); 585 | sprintf(lonstr, "%f", gir->longitude); 586 | geoip_say(cfg, r, "GEOIP_LATITUDE_V6", latstr); 587 | geoip_say(cfg, r, "GEOIP_LONGITUDE_V6", lonstr); 588 | geoip_say(cfg, r, "GEOIP_POSTAL_CODE_V6", gir->postal_code); 589 | GeoIPRecord_delete(gir); 590 | } 591 | 592 | break; 593 | case GEOIP_CITY_EDITION_REV0: 594 | case GEOIP_CITY_EDITION_REV1: 595 | gir = GeoIP_record_by_addr(cfg->gips[i], ipaddr); 596 | if (gir != NULL) { 597 | if (gir->country_code != NULL) { 598 | region_name = 599 | GeoIP_region_name_by_code(gir->country_code, 600 | gir->region); 601 | } 602 | sprintf(metrocodestr, "%d", gir->dma_code); 603 | sprintf(areacodestr, "%d", gir->area_code); 604 | geoip_say(cfg, r, "GEOIP_CONTINENT_CODE", gir->continent_code); 605 | geoip_say(cfg, r, "GEOIP_COUNTRY_CODE", gir->country_code); 606 | geoip_say(cfg, r, "GEOIP_COUNTRY_NAME", gir->country_name); 607 | geoip_say(cfg, r, "GEOIP_REGION", gir->region); 608 | geoip_say(cfg, r, "GEOIP_REGION_NAME", region_name); 609 | geoip_say(cfg, r, "GEOIP_CITY", gir->city); 610 | geoip_say(cfg, r, "GEOIP_DMA_CODE", metrocodestr); 611 | geoip_say(cfg, r, "GEOIP_METRO_CODE", metrocodestr); 612 | geoip_say(cfg, r, "GEOIP_AREA_CODE", areacodestr); 613 | sprintf(latstr, "%f", gir->latitude); 614 | sprintf(lonstr, "%f", gir->longitude); 615 | geoip_say(cfg, r, "GEOIP_LATITUDE", latstr); 616 | geoip_say(cfg, r, "GEOIP_LONGITUDE", lonstr); 617 | geoip_say(cfg, r, "GEOIP_POSTAL_CODE", gir->postal_code); 618 | GeoIPRecord_delete(gir); 619 | } 620 | 621 | break; 622 | case GEOIP_ORG_EDITION: 623 | orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); 624 | geoip_say(cfg, r, "GEOIP_ORGANIZATION", orgorisp); 625 | free(orgorisp); 626 | break; 627 | case GEOIP_ISP_EDITION: 628 | orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); 629 | geoip_say(cfg, r, "GEOIP_ISP", orgorisp); 630 | free(orgorisp); 631 | break; 632 | case GEOIP_DOMAIN_EDITION: 633 | orgorisp = GeoIP_name_by_addr(cfg->gips[i], ipaddr); 634 | geoip_say(cfg, r, "GEOIP_DOMAIN", orgorisp); 635 | free(orgorisp); 636 | break; 637 | } 638 | } 639 | 640 | return OK; 641 | } 642 | 643 | static const char *geoip_scanproxyfield(cmd_parms * cmd, void *dummy, 644 | const char *field) 645 | { 646 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 647 | ap_get_module_config( 648 | cmd->server->module_config, &geoip_module); 649 | 650 | if (!field) { 651 | return NULL; 652 | } 653 | 654 | conf->GeoIPProxyField = (char *)apr_pstrdup(cmd->pool, field); 655 | return NULL; 656 | } 657 | 658 | static const char *geoip_use_first_non_private_x_forwarded_for_ip(cmd_parms * 659 | cmd, 660 | void *dummy, 661 | int arg) 662 | { 663 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 664 | ap_get_module_config( 665 | cmd->server->module_config, &geoip_module); 666 | 667 | if (!conf) { 668 | return "mod_geoip: server structure not allocated"; 669 | } 670 | 671 | conf->proxyHeaderMode = 672 | arg ? GEOIP_PROXY_HEADER_MODE_FIRST_NON_PRIVATE_IP : 673 | GEOIP_PROXY_HEADER_MODE_DEFAULT; 674 | return NULL; 675 | } 676 | 677 | static const char *geoip_use_first_x_forwarded_for_ip(cmd_parms * cmd, 678 | void *dummy, int arg) 679 | { 680 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 681 | ap_get_module_config( 682 | cmd->server->module_config, &geoip_module); 683 | 684 | if (!conf) { 685 | return "mod_geoip: server structure not allocated"; 686 | } 687 | 688 | conf->proxyHeaderMode = 689 | arg ? GEOIP_PROXY_HEADER_MODE_FIRST_IP : 690 | GEOIP_PROXY_HEADER_MODE_DEFAULT; 691 | return NULL; 692 | } 693 | 694 | static const char *geoip_use_last_x_forwarded_for_ip(cmd_parms * cmd, 695 | void *dummy, int arg) 696 | { 697 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 698 | ap_get_module_config( 699 | cmd->server->module_config, &geoip_module); 700 | 701 | if (!conf) { 702 | return "mod_geoip: server structure not allocated"; 703 | } 704 | 705 | conf->proxyHeaderMode = 706 | arg ? GEOIP_PROXY_HEADER_MODE_LAST_IP : GEOIP_PROXY_HEADER_MODE_DEFAULT; 707 | return NULL; 708 | } 709 | 710 | static const char *geoip_scanproxy(cmd_parms * cmd, void *dummy, int arg) 711 | { 712 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 713 | ap_get_module_config( 714 | cmd->server->module_config, &geoip_module); 715 | 716 | if (!conf) { 717 | return "mod_geoip: server structure not allocated"; 718 | } 719 | 720 | conf->scanProxyHeaders = arg; 721 | return NULL; 722 | } 723 | 724 | static const char *set_geoip_enable(cmd_parms * cmd, void *dummy, int arg) 725 | { 726 | geoip_server_config_rec *conf; 727 | 728 | /* is per directory config? */ 729 | if (cmd->path) { 730 | geoip_dir_config_rec *dcfg = dummy; 731 | dcfg->GeoIPEnabled = arg; 732 | return NULL; 733 | } 734 | /* no then it is server config */ 735 | conf = (geoip_server_config_rec *) 736 | ap_get_module_config(cmd->server->module_config, &geoip_module); 737 | 738 | if (!conf) { 739 | return "mod_geoip: server structure not allocated"; 740 | } 741 | 742 | conf->GeoIPEnabled = arg; 743 | return NULL; 744 | } 745 | 746 | static const char *set_geoip_enable_utf8(cmd_parms * cmd, void *dummy, int arg) 747 | { 748 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 749 | ap_get_module_config( 750 | cmd->server->module_config, &geoip_module); 751 | 752 | if (!conf) { 753 | return "mod_geoip: server structure not allocated"; 754 | } 755 | 756 | conf->GeoIPEnableUTF8 = arg; 757 | return NULL; 758 | } 759 | 760 | static const char *set_geoip_filename(cmd_parms * cmd, void *dummy, 761 | const char *filename, const char *arg2) 762 | { 763 | int i; 764 | geoip_server_config_rec *conf = (geoip_server_config_rec *) 765 | ap_get_module_config( 766 | cmd->server->module_config, &geoip_module); 767 | 768 | if (!filename) { 769 | return NULL; 770 | } 771 | 772 | i = conf->numGeoIPFiles; 773 | conf->numGeoIPFiles++; 774 | conf->GeoIPFilenames = 775 | realloc(conf->GeoIPFilenames, conf->numGeoIPFiles * sizeof(char *)); 776 | conf->GeoIPFilenames[i] = (char *)apr_pstrdup(cmd->pool, filename); 777 | conf->GeoIPFlags2 = 778 | realloc(conf->GeoIPFlags2, conf->numGeoIPFiles * sizeof(int)); 779 | if (arg2 == NULL) { 780 | conf->GeoIPFlags2[i] = GEOIP_UNKNOWN; 781 | } else if (!strcmp(arg2, "Standard")) { 782 | conf->GeoIPFlags2[i] = GEOIP_STANDARD; 783 | } else if (!strcmp(arg2, "MemoryCache")) { 784 | conf->GeoIPFlags2[i] = GEOIP_MEMORY_CACHE; 785 | } else if (!strcmp(arg2, "CheckCache")) { 786 | conf->GeoIPFlags2[i] = GEOIP_CHECK_CACHE; 787 | } else if (!strcmp(arg2, "IndexCache")) { 788 | conf->GeoIPFlags2[i] = GEOIP_INDEX_CACHE; 789 | } else if (!strcmp(arg2, "MMapCache")) { 790 | conf->GeoIPFlags2[i] = GEOIP_MMAP_CACHE; 791 | } 792 | return NULL; 793 | } 794 | 795 | static const char *set_geoip_output_mode(cmd_parms * cmd, void *dummy, 796 | const char *arg) 797 | { 798 | geoip_server_config_rec *cfg = 799 | (geoip_server_config_rec *)ap_get_module_config(cmd-> 800 | server->module_config, 801 | &geoip_module); 802 | 803 | if (cfg->GeoIPOutput & GEOIP_DEFAULT) { 804 | /* was set to default, clear so can be reset with user specified values */ 805 | cfg->GeoIPOutput = GEOIP_NONE; 806 | } 807 | if (!strcmp(arg, "Notes")) { 808 | cfg->GeoIPOutput |= GEOIP_NOTES; 809 | } else if (!strcmp(arg, "Env")) { 810 | cfg->GeoIPOutput |= GEOIP_ENV; 811 | } else if (!strcmp(arg, "Request")) { 812 | cfg->GeoIPOutput |= GEOIP_REQUEST; 813 | } else if (!strcmp(arg, "All")) { 814 | cfg->GeoIPOutput |= GEOIP_ALL; 815 | } 816 | return NULL; 817 | } 818 | 819 | static void *make_geoip(apr_pool_t * p, server_rec * d) 820 | { 821 | geoip_server_config_rec *dcfg; 822 | 823 | dcfg = 824 | (geoip_server_config_rec *)apr_pcalloc(p, 825 | sizeof 826 | (geoip_server_config_rec)); 827 | dcfg->gips = NULL; 828 | dcfg->numGeoIPFiles = 0; 829 | dcfg->GeoIPFilenames = NULL; 830 | dcfg->GeoIPEnabled = 0; 831 | dcfg->GeoIPEnableUTF8 = 0; 832 | dcfg->GeoIPOutput = GEOIP_INIT; 833 | dcfg->GeoIPFlags = GEOIP_STANDARD; 834 | dcfg->GeoIPFlags2 = NULL; 835 | return dcfg; 836 | } 837 | 838 | static const command_rec geoip_cmds[] = { 839 | AP_INIT_FLAG("GeoIPScanProxyHeaders", 840 | geoip_scanproxy, 841 | NULL, 842 | RSRC_CONF, 843 | "Get IP from HTTP_CLIENT IP or X-Forwarded-For"), 844 | AP_INIT_TAKE1("GeoIPScanProxyHeaderField", 845 | geoip_scanproxyfield, 846 | NULL, 847 | RSRC_CONF, 848 | "Get IP from this header field, only"), 849 | AP_INIT_FLAG( 850 | "GeoIPUseFirstNonPrivateXForwardedForIP", 851 | geoip_use_first_non_private_x_forwarded_for_ip, 852 | NULL, 853 | RSRC_CONF, 854 | "For more IP's in X-Forwarded-For, use the first non private IP"), 855 | AP_INIT_FLAG("GeoIPUseFirstXForwardedForIP", 856 | geoip_use_first_x_forwarded_for_ip, 857 | NULL, 858 | RSRC_CONF, 859 | "For more IP's in X-Forwarded-For, use the first"), 860 | AP_INIT_FLAG("GeoIPUseLastXForwardedForIP", 861 | geoip_use_last_x_forwarded_for_ip, 862 | NULL, 863 | RSRC_CONF, 864 | "For more IP's in X-Forwarded-For, use the last"), 865 | AP_INIT_FLAG("GeoIPEnable", 866 | set_geoip_enable, 867 | NULL, 868 | RSRC_CONF | OR_FILEINFO, 869 | "Turn on mod_geoip"), 870 | AP_INIT_FLAG("GeoIPEnableUTF8", 871 | set_geoip_enable_utf8, 872 | NULL, 873 | RSRC_CONF, 874 | "Turn on utf8 characters for city names"), 875 | AP_INIT_TAKE12("GeoIPDBFile", 876 | set_geoip_filename, 877 | NULL, 878 | RSRC_CONF, 879 | "Path to GeoIP Data File"), 880 | AP_INIT_ITERATE("GeoIPOutput", 881 | set_geoip_output_mode, 882 | NULL, 883 | RSRC_CONF, 884 | "Specify output method(s)"), 885 | { NULL } 886 | }; 887 | 888 | static void geoip_register_hooks(apr_pool_t * p) 889 | { 890 | /* make sure we run before mod_rewrite's handler */ 891 | static const char *const aszSucc[] = 892 | { "mod_setenvif.c", "mod_rewrite.c", NULL }; 893 | 894 | /* we have two entry points, the header_parser hook, right before 895 | * the authentication hook used for Dirctory specific enabled geoiplookups 896 | * or right before directory rewrite rules. 897 | */ 898 | ap_hook_header_parser(geoip_per_dir, NULL, aszSucc, APR_HOOK_FIRST); 899 | 900 | /* and the servectly wide hook, after reading the request. Perfecly 901 | * suitable to serve serverwide mod_rewrite actions 902 | */ 903 | ap_hook_post_read_request(geoip_post_read_request, NULL, aszSucc, 904 | APR_HOOK_MIDDLE); 905 | 906 | /* setup our childs GeoIP database once for every child */ 907 | ap_hook_child_init(geoip_child_init, NULL, NULL, APR_HOOK_MIDDLE); 908 | 909 | /* static const char * const list[]={ "mod_geoip.c", NULL }; */ 910 | /* mmap the database(s) into the master process */ 911 | ap_hook_post_config(geoip_post_config, NULL, NULL, APR_HOOK_MIDDLE); 912 | 913 | } 914 | 915 | /* Dispatch list for API hooks */ 916 | module AP_MODULE_DECLARE_DATA geoip_module = { 917 | STANDARD20_MODULE_STUFF, 918 | geoip_create_dir_config, /* create per-dir config structures */ 919 | NULL, /* merge per-dir config structures */ 920 | make_geoip, /* create per-server config structures */ 921 | NULL, /* merge per-server config structures */ 922 | geoip_cmds, /* table of config file commands */ 923 | geoip_register_hooks /* register hooks */ 924 | }; 925 | --------------------------------------------------------------------------------