├── .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 |
--------------------------------------------------------------------------------