Codebase list libapache2-mod-rpaf / 7e13762
Imported Upstream version 0.6 Sergey B Kirpichev 12 years ago
13 changed file(s) with 1033 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Keep Alive Problem reported and patched by Christian Schneider
1 Also reported by Hiroyuki OYAMA and Vladimir Klebanov
2 mod_rpaf was incorrectly using r->pool to allocate memory for the
3 ip. The correct pool for this when you are dealing wth keep-alive
4 requests was r->connection->pool.
5
6 Adding configurable header to work with common Russian setups that
7 use X-Real-Ip instead of X-Forwarded-For.
8
9 Fixing problems with keep-alive connections reusing the original
10 X-Forwarded-For ip as the 'remote_ip'.
11
12 Move the `change_remote_ip' handler from being APR_HOOK_MIDDLE to
13 APR_HOOK_FIRST to make the module run before modules like mod_geoip.
14
15 Thanks to bug reports from
16
17 Yar Odin
18 Michael Cramer
19 Sridhar Komandur
20 Heddy Boubaker
21 Mitar
22 Sergey Mokryshev
23 Günter Knaf
0 # Makefile for mod_rpaf.c (gmake)
1 # $Id: Makefile 16 2007-12-13 03:40:22Z thomas $
2 APXS=$(shell which apxs)
3 APXS2=$(shell which apxs2)
4
5 default:
6 @echo mod_rpaf:
7 @echo nevest version available at http://stderr.net/apache/rpaf/
8 @echo
9 @echo following options available:
10 @echo \"make rpaf\" to compile the 1.3 version
11 @echo \"make test\" to test 1.3 version
12 @echo \"make install\" to install the 1.3 version
13 @echo \"make rpaf-2.0\" to compile the 2.0 version
14 @echo \"make test-2.0\" to test 2.0 version
15 @echo \"make install-2.0\" to install the 2.0 version
16 @echo
17 @echo change path to apxs if this is not it: \"$(APXS)\"
18
19
20 rpaf: mod_rpaf.so
21 @echo make done
22 @echo type \"make test\" to test mod_rpaf
23 @echo type \"make install\" to install mod_rpaf
24
25 test: rpaf
26 @./gen_tests.sh
27 cd t && $(MAKE) test
28 @echo all done
29
30 rpaf-2.0: mod_rpaf-2.0.o
31 @echo make done, type \"make install-2.0\" to install mod_rpaf-2.0
32
33 test-2.0: rpaf-2.0
34 @./gen_tests.sh
35 cd t && make test-2.0
36
37 mod_rpaf.so: mod_rpaf.c
38 $(APXS) -c -o $@ mod_rpaf.c
39
40 mod_rpaf.c:
41
42 mod_rpaf-2.0.o: mod_rpaf-2.0.c
43 $(APXS2) -c -n $@ mod_rpaf-2.0.c
44
45 mod_rpaf-2.0.c:
46
47 install: mod_rpaf.so
48 $(APXS) -i -n mod_rpaf mod_rpaf.so
49
50 install-2.0: mod_rpaf-2.0.o
51 $(APXS2) -i -n mod_rpaf-2.0.so mod_rpaf-2.0.la
52
53 clean:
54 rm -rf *~ *.o *.so *.lo *.la *.slo *.loT .libs/
55 cd t && make clean
0 mod_rpaf - reverse proxy add forward
1
2 This module does the opposite of mod_proxy_add_forward written
3 by Ask Bjørn Hansen. http://develooper.com/code/mpaf/
4
5 Compile and Install for 1.3:
6
7 apxs -i -a -c mod_rpaf.c
8
9 Compile and Install for 2.0:
10
11 apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c
12
13 or simply try:
14 make
15
16 Configuration Directives:
17 RPAFenable On
18 # Enable reverse proxy add forward
19 RPAFproxy_ips 127.0.0.1 10.0.0.1
20 # which ips are forwarding requests to us
21 RPAFsethostname On
22 # let rpaf update vhost settings
23 # allows to have the same hostnames as in the "real"
24 # configuration for the forwarding Apache
25 RPAFheader X-Forwarded-For
26 # Allows you to change which header mod_rpaf looks
27 # for when trying to find the ip the that is forwarding
28 # our requests
29
30 Author:
31 Thomas Eibner <thomas@stderr.net>
32
33 License:
34 Apache License
35
36 Latest version available from:
37 http://stderr.net/apache/rpaf/
0 #!/bin/sh
1 PATH=$PATH:/home/thomas/build/apache-dev/bin
2 DIRECTORY=`pwd`/t
3 HTTPD=`which httpd`
4 HTTPD2=`which apache2`
5
6 cat test-Makefile-template | sed -s "s|\@\@HTTPD\@\@|$HTTPD|" | sed -s "s|\@\@HTTPD2\@\@|$HTTPD2|" > t/Makefile
7
8
9 if [ "$HTTPD" != "" ]; then
10 echo "Found httpd as $HTTPD"
11 echo "Creating test configuration for apache 1.3.x"
12 echo "in directory $DIRECTORY"
13 cat httpd-rpaf.conf-template | sed -s "s|\@\@DIR\@\@|$DIRECTORY|" > t/httpd-rpaf.conf
14 fi
15
16 APACHE2=`which apache2`
17
18 if [ "$APACHE2" != "" ]; then
19 echo "Found apache2 as $HTTPD"
20 echo "Creating test configuration for apache 2.x.x"
21 echo "in directory $DIRECTORY"
22 cat httpd-rpaf.conf-template-2.0 | sed -s "s|\@\@DIR\@\@|$DIRECTORY|" > t/httpd-rpaf.conf-2.0
23 fi
24
25
0 ServerType standalone
1 PidFile httpd.pid
2 Port 2500
3 ServerName 127.0.0.1
4 #ServerRoot @@DIR@@
5 DocumentRoot @@DIR@@/htdocs/
6 ErrorLog rpaf-error_log
7 LoadModule rpaf_module ../mod_rpaf.so
8 ScriptAlias /cgi-bin @@DIR@@/htdocs/cgi-bin
9 TypesConfig /dev/null
10 <IfDefine test1>
11 RPAFenable Off
12 </IfDefine>
13 <IfDefine test2>
14 RPAFenable On
15 RPAFsethostname Off
16 RPAFproxy_ips 127.0.0.1
17 </IfDefine>
18 <IfDefine test3>
19 RPAFenable On
20 RPAFsethostname On
21 RPAFproxy_ips 127.0.0.1
22 </IfDefine>
23 <IfDefine test4>
24 RPAFenable On
25 RPAFsethostname On
26 RPAFproxy_ips 127.0.0.1
27 RPAFheader X-Forwarded-For
28 </IfDefine>
29 <IfDefine test5>
30 RPAFenable On
31 RPAFsethostname On
32 RPAFproxy_ips 127.0.0.1
33 RPAFheader X-Real-IP
34 </IfDefine>
35 <IfDefine test6>
36 RPAFenable On
37 RPAFsethostname On
38 RPAFproxy_ips 127.0.0.1
39 KeepAlive On
40 KeepAlivetimeout 15
41 LogFormat "%h" rpaf
42 CustomLog rpaf-access_log rpaf
43 </IfDefine>
44 <IfDefine test7>
45 RPAFenable On
46 RPAFsethostname On
47 RPAFproxy_ips 127.0.0.1
48 KeepAlive On
49 KeepAlivetimeout 15
50 LogFormat "%h" rpaf
51 CustomLog rpaf-access_log rpaf
52 HostNameLookups On
53 </IfDefine>
0 PidFile httpd.pid
1 Listen 2500
2 ServerName 127.0.0.1
3 #ServerRoot @@DIR@@
4 DocumentRoot @@DIR@@/htdocs/
5 ErrorLog rpaf-error_log
6 LoadModule rpaf_module @@DIR@@/../.libs/mod_rpaf-2.0.so
7 LoadModule cgi_module /usr/lib/apache2/modules/mod_cgi.so
8 LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so
9 ScriptAlias /cgi-bin @@DIR@@/htdocs/cgi-bin
10 <IfDefine test1>
11 RPAFenable Off
12 </IfDefine>
13 <IfDefine test2>
14 RPAFenable On
15 RPAFsethostname Off
16 RPAFproxy_ips 127.0.0.1
17 </IfDefine>
18 <IfDefine test3>
19 RPAFenable On
20 RPAFsethostname On
21 RPAFproxy_ips 127.0.0.1
22 </IfDefine>
23 <IfDefine test4>
24 RPAFenable On
25 RPAFsethostname On
26 RPAFproxy_ips 127.0.0.1
27 RPAFheader X-Forwarded-For
28 </IfDefine>
29 <IfDefine test5>
30 RPAFenable On
31 RPAFsethostname On
32 RPAFproxy_ips 127.0.0.1
33 RPAFheader X-Real-IP
34 </IfDefine>
35 <IfDefine test6>
36 RPAFenable On
37 RPAFsethostname On
38 RPAFproxy_ips 127.0.0.1
39 KeepAlive On
40 KeepAliveTimeout 15
41 LogFormat "%h" rpaf
42 CustomLog rpaf-access_log rpaf
43 </IfDefine>
44 <IfDefine test7>
45 RPAFenable On
46 RPAFsethostname On
47 RPAFproxy_ips 127.0.0.1
48 KeepAlive On
49 KeepAliveTimeout 15
50 LogFormat "%h" rpaf
51 CustomLog rpaf-access_log rpaf
52 HostNameLookups On
53 </IfDefine>
0
1 /* ====================================================================
2 * Copyright (c) 1995 The Apache Group. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the Apache Group
19 * for use in the Apache HTTP server project (http://www.apache.org/)."
20 *
21 * 4. The names "Apache Server" and "Apache Group" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission.
24 *
25 * 5. Redistributions of any form whatsoever must retain the following
26 * acknowledgment:
27 * "This product includes software developed by the Apache Group
28 * for use in the Apache HTTP server project (http://www.apache.org/)."
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
31 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
34 * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ====================================================================
43 *
44 * This software consists of voluntary contributions made by many
45 * individuals on behalf of the Apache Group and was originally based
46 * on public domain software written at the National Center for
47 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
48 * For more information on the Apache Group and the Apache HTTP server
49 * project, please see <http://www.apache.org/>.
50 *
51 */
52
53 /*
54 * $Id: mod_rpaf-2.0.c 18 2008-01-01 03:05:40Z thomas $
55 *
56 * Author: Thomas Eibner, <thomas@stderr.net>
57 * URL: http://stderr.net/apache/rpaf/
58 * rpaf is short for reverse proxy add forward
59 *
60 * This module does the opposite of mod_proxy_add_forward written by
61 * Ask Bjørn Hansen. http://develooper.com/code/mpaf/ or mod_proxy
62 * in 1.3.25 and above and mod_proxy from Apache 2.0
63 *
64 */
65
66 #include "httpd.h"
67 #include "http_config.h"
68 #include "http_core.h"
69 #include "http_log.h"
70 #include "http_protocol.h"
71 #include "http_vhost.h"
72 #include "apr_strings.h"
73
74 module AP_MODULE_DECLARE_DATA rpaf_module;
75
76 typedef struct {
77 int enable;
78 int sethostname;
79 const char *headername;
80 apr_array_header_t *proxy_ips;
81 } rpaf_server_cfg;
82
83 typedef struct {
84 const char *old_ip;
85 request_rec *r;
86 } rpaf_cleanup_rec;
87
88 static void *rpaf_create_server_cfg(apr_pool_t *p, server_rec *s) {
89 rpaf_server_cfg *cfg = (rpaf_server_cfg *)apr_pcalloc(p, sizeof(rpaf_server_cfg));
90 if (!cfg)
91 return NULL;
92
93 cfg->proxy_ips = apr_array_make(p, 0, sizeof(char *));
94 cfg->enable = 0;
95 cfg->sethostname = 0;
96
97 return (void *)cfg;
98 }
99
100 static const char *rpaf_set_proxy_ip(cmd_parms *cmd, void *dummy, const char *proxy_ip) {
101 server_rec *s = cmd->server;
102 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
103 &rpaf_module);
104
105 /* check for valid syntax of ip */
106 *(char **)apr_array_push(cfg->proxy_ips) = apr_pstrdup(cmd->pool, proxy_ip);
107 return NULL;
108 }
109
110 static const char *rpaf_set_headername(cmd_parms *cmd, void *dummy, const char *headername) {
111 server_rec *s = cmd->server;
112 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
113 &rpaf_module);
114
115 cfg->headername = headername;
116 return NULL;
117 }
118
119 static const char *rpaf_enable(cmd_parms *cmd, void *dummy, int flag) {
120 server_rec *s = cmd->server;
121 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
122 &rpaf_module);
123
124 cfg->enable = flag;
125 return NULL;
126 }
127
128 static const char *rpaf_sethostname(cmd_parms *cmd, void *dummy, int flag) {
129 server_rec *s = cmd->server;
130 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
131 &rpaf_module);
132
133 cfg->sethostname = flag;
134 return NULL;
135 }
136
137 static int is_in_array(const char *remote_ip, apr_array_header_t *proxy_ips) {
138 int i;
139 char **list = (char**)proxy_ips->elts;
140 for (i = 0; i < proxy_ips->nelts; i++) {
141 if (strcmp(remote_ip, list[i]) == 0)
142 return 1;
143 }
144 return 0;
145 }
146
147 static apr_status_t rpaf_cleanup(void *data) {
148 rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)data;
149 rcr->r->connection->remote_ip = apr_pstrdup(rcr->r->connection->pool, rcr->old_ip);
150 rcr->r->connection->remote_addr->sa.sin.sin_addr.s_addr = apr_inet_addr(rcr->r->connection->remote_ip);
151 return APR_SUCCESS;
152 }
153
154 static int change_remote_ip(request_rec *r) {
155 const char *fwdvalue;
156 char *val;
157 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(r->server->module_config,
158 &rpaf_module);
159
160 if (!cfg->enable)
161 return DECLINED;
162
163 if (is_in_array(r->connection->remote_ip, cfg->proxy_ips) == 1) {
164 /* check if cfg->headername is set and if it is use
165 that instead of X-Forwarded-For by default */
166 if (cfg->headername && (fwdvalue = apr_table_get(r->headers_in, cfg->headername))) {
167 //
168 } else if (fwdvalue = apr_table_get(r->headers_in, "X-Forwarded-For")) {
169 //
170 } else {
171 return DECLINED;
172 }
173
174 if (fwdvalue) {
175 rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)apr_pcalloc(r->pool, sizeof(rpaf_cleanup_rec));
176 apr_array_header_t *arr = apr_array_make(r->pool, 0, sizeof(char*));
177 while (*fwdvalue && (val = ap_get_token(r->pool, &fwdvalue, 1))) {
178 *(char **)apr_array_push(arr) = apr_pstrdup(r->pool, val);
179 if (*fwdvalue != '\0')
180 ++fwdvalue;
181 }
182 rcr->old_ip = apr_pstrdup(r->connection->pool, r->connection->remote_ip);
183 rcr->r = r;
184 apr_pool_cleanup_register(r->pool, (void *)rcr, rpaf_cleanup, apr_pool_cleanup_null);
185 r->connection->remote_ip = apr_pstrdup(r->connection->pool, ((char **)arr->elts)[((arr->nelts)-1)]);
186 r->connection->remote_addr->sa.sin.sin_addr.s_addr = apr_inet_addr(r->connection->remote_ip);
187 if (cfg->sethostname) {
188 const char *hostvalue;
189 if (hostvalue = apr_table_get(r->headers_in, "X-Forwarded-Host")) {
190 /* 2.0 proxy frontend or 1.3 => 1.3.25 proxy frontend */
191 apr_table_set(r->headers_in, "Host", apr_pstrdup(r->pool, hostvalue));
192 r->hostname = apr_pstrdup(r->pool, hostvalue);
193 ap_update_vhost_from_headers(r);
194 } else if (hostvalue = apr_table_get(r->headers_in, "X-Host")) {
195 /* 1.3 proxy frontend with mod_proxy_add_forward */
196 apr_table_set(r->headers_in, "Host", apr_pstrdup(r->pool, hostvalue));
197 r->hostname = apr_pstrdup(r->pool, hostvalue);
198 ap_update_vhost_from_headers(r);
199 }
200 }
201
202 }
203 }
204 return DECLINED;
205 }
206
207 static const command_rec rpaf_cmds[] = {
208 AP_INIT_FLAG(
209 "RPAFenable",
210 rpaf_enable,
211 NULL,
212 RSRC_CONF,
213 "Enable mod_rpaf"
214 ),
215 AP_INIT_FLAG(
216 "RPAFsethostname",
217 rpaf_sethostname,
218 NULL,
219 RSRC_CONF,
220 "Let mod_rpaf set the hostname from X-Host header and update vhosts"
221 ),
222 AP_INIT_ITERATE(
223 "RPAFproxy_ips",
224 rpaf_set_proxy_ip,
225 NULL,
226 RSRC_CONF,
227 "IP(s) of Proxy server setting X-Forwarded-For header"
228 ),
229 AP_INIT_TAKE1(
230 "RPAFheader",
231 rpaf_set_headername,
232 NULL,
233 RSRC_CONF,
234 "Which header to look for when trying to find the real ip of the client in a proxy setup"
235 ),
236 { NULL }
237 };
238
239 static void register_hooks(apr_pool_t *p) {
240 ap_hook_post_read_request(change_remote_ip, NULL, NULL, APR_HOOK_FIRST);
241 }
242
243 module AP_MODULE_DECLARE_DATA rpaf_module = {
244 STANDARD20_MODULE_STUFF,
245 NULL,
246 NULL,
247 rpaf_create_server_cfg,
248 NULL,
249 rpaf_cmds,
250 register_hooks,
251 };
0
1 /* ====================================================================
2 * Copyright (c) 1995 The Apache Group. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the Apache Group
19 * for use in the Apache HTTP server project (http://www.apache.org/)."
20 *
21 * 4. The names "Apache Server" and "Apache Group" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission.
24 *
25 * 5. Redistributions of any form whatsoever must retain the following
26 * acknowledgment:
27 * "This product includes software developed by the Apache Group
28 * for use in the Apache HTTP server project (http://www.apache.org/)."
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
31 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
34 * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ====================================================================
43 *
44 * This software consists of voluntary contributions made by many
45 * individuals on behalf of the Apache Group and was originally based
46 * on public domain software written at the National Center for
47 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
48 * For more information on the Apache Group and the Apache HTTP server
49 * project, please see <http://www.apache.org/>.
50 *
51 */
52
53 /*
54 * $Id: mod_rpaf.c 17 2008-01-01 03:03:15Z thomas $
55 *
56 * Author: Thomas Eibner, <thomas@stderr.net>
57 * URL: http://stderr.net/apache/rpaf/
58 * rpaf is short for reverse proxy add forward
59 *
60 * This module does the opposite of mod_proxy_add_forward written by
61 * Ask Bjørn Hansen. http://develooper.com/code/mpaf/ or mod_proxy
62 * in 1.3.25 and above and mod_proxy from Apache 2.0
63 *
64 */
65
66 #include "httpd.h"
67 #include "http_config.h"
68 #include "http_core.h"
69 #include "http_log.h"
70 #include "http_protocol.h"
71 #include "http_vhost.h"
72
73 module MODULE_VAR_EXPORT rpaf_module;
74
75 typedef struct {
76 int enable;
77 int sethostname;
78 const char *headername;
79 array_header *proxy_ips;
80 } rpaf_server_cfg;
81
82 typedef struct {
83 const char *old_ip;
84 request_rec *r;
85 } rpaf_cleanup_rec;
86
87 static void *rpaf_create_server_cfg(pool *p, server_rec *s) {
88 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_pcalloc(p, sizeof(rpaf_server_cfg));
89 if (!cfg)
90 return NULL;
91
92 cfg->proxy_ips = ap_make_array(p, 0, sizeof(char *));
93 cfg->enable = 0;
94 cfg->sethostname = 0;
95
96 return (void *)cfg;
97 }
98
99 static const char *rpaf_set_proxy_ip(cmd_parms *cmd, void *dummy, char *proxy_ip) {
100 server_rec *s = cmd->server;
101 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
102 &rpaf_module);
103
104 /* check for valid syntax of ip */
105
106 *(char **)ap_push_array(cfg->proxy_ips) = ap_pstrdup(cmd->pool, proxy_ip);
107 return NULL;
108 }
109
110 static const char *rpaf_set_headername(cmd_parms *cmd, void *dummy, char *headername) {
111 server_rec *s = cmd->server;
112 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
113 &rpaf_module);
114
115 cfg->headername = headername;
116 return NULL;
117 }
118
119 static const char *rpaf_enable(cmd_parms *cmd, void *dummy, int flag) {
120 server_rec *s = cmd->server;
121 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
122 &rpaf_module);
123
124 cfg->enable = flag;
125 return NULL;
126 }
127
128 static const char *rpaf_sethostname(cmd_parms *cmd, void *dummy, int flag) {
129 server_rec *s = cmd->server;
130 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(s->module_config,
131 &rpaf_module);
132
133 cfg->sethostname = flag;
134 return NULL;
135 }
136
137 static int is_in_array(const char *remote_ip, array_header *proxy_ips) {
138 int i;
139 char **list = (char**)proxy_ips->elts;
140 for (i = 0; i < proxy_ips->nelts; i++) {
141 if (strcmp(remote_ip, list[i]) == 0)
142 return 1;
143 }
144 return 0;
145 }
146
147 static void rpaf_cleanup(void *data) {
148 rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)data;
149 rcr->r->connection->remote_ip = ap_pstrdup(rcr->r->connection->pool, rcr->old_ip);
150 rcr->r->connection->remote_addr.sin_addr.s_addr = inet_addr(rcr->r->connection->remote_ip);
151 }
152
153 static int change_remote_ip(request_rec *r) {
154 const char *fwdvalue;
155 char *val;
156 rpaf_server_cfg *cfg = (rpaf_server_cfg *)ap_get_module_config(r->server->module_config,
157 &rpaf_module);
158
159 if (!cfg->enable)
160 return DECLINED;
161
162 if (is_in_array(r->connection->remote_ip, cfg->proxy_ips) == 1) {
163 /* check if cfg->headername is set and if it is use
164 that instead of X-Forwarded-For by default */
165 if (cfg->headername && (fwdvalue = ap_table_get(r->headers_in, cfg->headername))) {
166 //
167 } else if (fwdvalue = ap_table_get(r->headers_in, "X-Forwarded-For")) {
168 //
169 } else {
170 return DECLINED;
171 }
172
173 if (fwdvalue) {
174 rpaf_cleanup_rec *rcr = (rpaf_cleanup_rec *)ap_pcalloc(r->pool, sizeof(rpaf_cleanup_rec));
175 array_header *arr = ap_make_array(r->pool, 0, sizeof(char*));
176 while (*fwdvalue && (val = ap_get_token(r->pool, &fwdvalue, 1))) {
177 *(char **)ap_push_array(arr) = ap_pstrdup(r->pool, val);
178 if (*fwdvalue != '\0')
179 ++fwdvalue;
180 }
181 rcr->old_ip = ap_pstrdup(r->connection->pool, r->connection->remote_ip);
182 rcr->r = r;
183 ap_register_cleanup(r->pool, (void *)rcr, rpaf_cleanup, ap_null_cleanup);
184 r->connection->remote_ip = ap_pstrdup(r->connection->pool, ((char **)arr->elts)[((arr->nelts)-1)]);
185 r->connection->remote_addr.sin_addr.s_addr = inet_addr(r->connection->remote_ip);
186 if (cfg->sethostname) {
187 const char *hostvalue;
188 if (hostvalue = ap_table_get(r->headers_in, "X-Forwarded-Host")) {
189 /* 2.0 proxy frontend or 1.3 => 1.3.25 proxy frontend */
190 ap_table_set(r->headers_in, "Host", ap_pstrdup(r->pool, hostvalue));
191 r->hostname = ap_pstrdup(r->pool, hostvalue);
192 ap_update_vhost_from_headers(r);
193 } else if (hostvalue = ap_table_get(r->headers_in, "X-Host")) {
194 /* 1.3 proxy frontend with mod_proxy_add_forward */
195 ap_table_set(r->headers_in, "Host", ap_pstrdup(r->pool, hostvalue));
196 r->hostname = ap_pstrdup(r->pool, hostvalue);
197 ap_update_vhost_from_headers(r);
198 }
199 }
200 }
201 }
202 return DECLINED;
203 }
204
205 static command_rec rpaf_cmds[] = {
206 { "RPAFenable", rpaf_enable, NULL,
207 RSRC_CONF, FLAG, "Enable mod_rpaf" },
208 { "RPAFsethostname", rpaf_sethostname, NULL,
209 RSRC_CONF, FLAG, "Let mod_rpaf set the hostname from the X-Host header and update vhosts" },
210 { "RPAFproxy_ips", rpaf_set_proxy_ip, NULL,
211 RSRC_CONF, ITERATE, "IP(s) of Proxy server setting X-Forwarded-For header" },
212 { "RPAFheader", rpaf_set_headername, NULL,
213 RSRC_CONF, TAKE1, "Which header to look for when trying to find the real ip of the client in a proxy setup" },
214 { NULL }
215 };
216
217 module MODULE_VAR_EXPORT rpaf_module = {
218 STANDARD_MODULE_STUFF,
219 NULL, /* initializer */
220 NULL, /* dir config creator */
221 NULL, /* dir config merger */
222 rpaf_create_server_cfg, /* server config */
223 NULL, /* merge server config */
224 rpaf_cmds, /* command table */
225 NULL, /* handlers */
226 NULL, /* filename translation */
227 NULL, /* check_user_id */
228 NULL, /* check auth */
229 NULL, /* check access */
230 NULL, /* type_checker */
231 NULL, /* fixups */
232 NULL, /* logger */
233 NULL, /* header parser */
234 NULL, /* child_init */
235 NULL, /* child_exit */
236 change_remote_ip /* post read-request */
237 };
238
239
0 #!/usr/bin/perl
1 # $Id: env.cgi 13 2007-11-26 00:19:53Z thomas $
2 print qq{Content-Type: text/plain\r\n\r\n};
3 print qq{HTTP_X_FORWARDED_FOR = } . (defined($ENV{HTTP_X_FORWARDED_FOR}) ? $ENV{HTTP_X_FORWARDED_FOR} : '');
4 print qq{\n};
5 print qq{REMOTE_ADDR = } . (defined($ENV{REMOTE_ADDR}) ? $ENV{REMOTE_ADDR} : '');
6 print qq{\n};
7 print qq{HTTP_HOST = } . (defined($ENV{HTTP_HOST}) ? $ENV{HTTP_HOST} : '');
8 print qq{\n};
9 print qq{HTTP_X_REAL_IP = } . (defined($ENV{HTTP_X_REAL_IP}) ? $ENV{HTTP_X_REAL_IP} : '');
10 print qq{\n};
0 <html>
1 test
2 </html>
0 #!/bin/sh
1
2 ~/build/apache-dev/bin/httpd -d . -f `pwd`/httpd-rpaf.conf -X
0 #!/usr/bin/perl
1
2 use strict;
3 use warnings;
4 use Data::Dumper;
5 use LWP::UserAgent;
6 use HTTP::Request;
7
8 my $localhost_ip = '127.0.0.1';
9 my $forward_ip = '140.211.11.130';
10 my $x_forwarded_for = "$localhost_ip; $forward_ip";
11 my $http_host = "$localhost_ip:2500";
12 my $x_host = 'www.apache.org';
13
14 my $test = shift || die("Missing a testcase");
15 my $ua;
16 if ($test ne 'test6') {
17 $ua = LWP::UserAgent->new();
18 } else {
19 $ua = LWP::UserAgent->new(keep_alive => 1);
20 }
21 my $request = HTTP::Request->new(GET => 'http://127.0.0.1:2500/cgi-bin/env.cgi');
22
23 run_test1() if $test eq 'test1';
24 run_test2() if $test eq 'test2';
25 run_test3() if $test eq 'test3';
26 run_test4() if $test eq 'test4';
27 run_test5() if $test eq 'test5';
28 run_test6() if $test eq 'test6';
29 run_test6() if $test eq 'test7';
30
31 sub run_test1 {
32 # two tests - one without X-Forwarded-For and one with
33
34 execute_test($request, { REMOTE_ADDR => $localhost_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => ''});
35
36 $request->header('X-Forwarded-For' => $x_forwarded_for);
37 execute_test($request, { REMOTE_ADDR => $localhost_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
38 }
39
40 sub run_test2 {
41 # three tests - one without X-Forwarded-For; one with; and one with X-Host
42
43 execute_test($request, { REMOTE_ADDR => $localhost_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => ''});
44
45 $request->header('X-Forwarded-For' => $x_forwarded_for);
46 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
47
48 $request->header('X-Host' => $x_host);
49 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
50 }
51
52 sub run_test3 {
53 # three tests one without X-Host; one with; and one with X-Forwarded-Host
54
55 $request->header('X-Forwarded-For' => $x_forwarded_for);
56 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
57
58 $request->header('X-Host' => $x_host);
59 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $x_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
60
61 $request->remove_header('X-Host');
62 $request->header('X-Forwarded-Host' => $x_host);
63 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $x_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
64 }
65
66 sub run_test4 {
67 # three tests one without X-Host; one with; and one with X-Forwarded-Host
68
69 $request->header('X-Forwarded-For' => $x_forwarded_for);
70 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $http_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
71
72 $request->header('X-Host' => $x_host);
73 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $x_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
74
75 $request->remove_header('X-Host');
76 $request->header('X-Forwarded-Host' => $x_host);
77 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $x_host, HTTP_X_FORWARDED_FOR => $x_forwarded_for});
78 }
79
80 sub run_test5 {
81 # two tests with X-Real-IP; one without X-Host; one with
82 $request->remove_header('X-Forwarded-For');
83 $request->header('X-Real-IP' => $x_forwarded_for);
84 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $http_host, HTTP_X_REAL_IP => $x_forwarded_for});
85
86 $request->header('X-Host' => $x_host);
87 execute_test($request, { REMOTE_ADDR => $forward_ip, HTTP_HOST => $x_host, HTTP_X_REAL_IP => $x_forwarded_for});
88
89 }
90
91 sub run_test6 {
92 # attempt to test keep-alive
93 print "Testing Keep-Alive\n";
94 my $static_request = HTTP::Request->new(GET => 'http://127.0.0.1:2500/index.html');
95 print "First using X-F-F: $x_forwarded_for\n";
96 $static_request->header('X-Forwarded-For' => $x_forwarded_for);
97 my $response = $ua->request($static_request);
98 if ($response->is_success()) {
99
100 } else {
101 print "Something went wrong in requesting file..";
102 }
103 my $reverse_xff = "$localhost_ip; " . (join ".", reverse split /\./, $forward_ip);
104 print "Then using X-F-F: $reverse_xff\n";
105 $static_request->header('X-Forwarded-For' => $reverse_xff);
106 $response = $ua->request($static_request);
107 if ($response->is_success()) {
108
109 } else {
110 print "Something went wrong in requesting file..";
111 }
112 print "Now requesting without X-F-F\n";
113 $static_request->remove_header('X-Forwarded-For');
114 $response = $ua->request($static_request);
115 if ($response->is_success()) {
116
117 } else {
118 print "Something went wrong in requesting file..";
119 }
120 print "Done\n";
121 }
122
123
124 sub execute_test {
125 my $request = shift;
126 my $expected = shift;
127
128 my $response = $ua->request($request);
129 if ($response->is_success()) {
130 my $returned = {};
131 my $content = $response->content();
132 my @rows = split /\n/, $content;
133 foreach my $row (@rows) {
134 my ($key,$value) = split / \= /, $row;
135 $returned->{$key} = $value;
136 }
137 # compare with $expected
138 foreach my $key (sort keys %$expected) {
139 print qq{Expected $key "$expected->{$key}" };
140 print qq{Response "$returned->{$key}" } if defined($returned->{$key});
141 my $status = (defined($returned->{$key}) && $returned->{$key} eq $expected->{$key} ? 'OK' : 'NOT OK' );
142 print qq{$status\n};
143 die(Dumper($response)) if $status ne 'OK';
144 }
145 # Everything looks like it worked
146 print qq{*** Test passed ***\n};
147 } else {
148 die($response);
149 }
150 }
0 # Makefile for mod_rpaf.c tests (gmake)
1 # $Id: test-Makefile-template 19 2008-01-02 02:55:18Z thomas $
2 HTTPD=@@HTTPD@@ -d . -f httpd-rpaf.conf -X
3 HTTPD2=@@HTTPD2@@ -d . -f httpd-rpaf.conf-2.0 -X
4
5 default:
6 @echo please run make test or make test-2.0
7 @echo from the root directory of your rpaf sources
8
9 test:
10 rm -f rpaf-error_log rpaf_access_log
11 @echo running rpaf apache 1.3.x tests
12 @echo test 1 - no rpaf
13 @echo starting apache ..
14 @$(HTTPD) -D test1 &
15 @./run_test.pl test1
16 @echo stopping apache ..
17 @kill -HUP `cat httpd.pid`
18 @rm httpd.pid
19 @echo test 2 - rpaf enabled
20 @echo starting apache ..
21 @$(HTTPD) -D test2 &
22 @./run_test.pl test2
23 @echo stopping apache ..
24 @kill -HUP `cat httpd.pid`
25 @rm httpd.pid
26 @echo test 3 - rpaf enabled - sethostname enabled
27 @echo starting apache ..
28 @$(HTTPD) -D test3 &
29 @./run_test.pl test3
30 @echo stopping apache ..
31 @kill -HUP `cat httpd.pid`
32 @rm httpd.pid
33 @echo test 4 - rpaf enabled - sethostname enabled - specifying header
34 @echo setting X-Forwarded-For
35 @echo starting apache ..
36 @$(HTTPD) -D test4 &
37 @./run_test.pl test4
38 @echo stopping apache ..
39 @kill -HUP `cat httpd.pid`
40 @rm httpd.pid
41 @echo test 5 - rpaf enabled - sethostname enabled - specifying header
42 @echo setting X-Real-IP
43 @echo starting apache ..
44 @$(HTTPD) -D test5 &
45 @./run_test.pl test5
46 @echo stopping apache ..
47 @kill -HUP `cat httpd.pid`
48 @rm httpd.pid
49 @echo test 6 - X-Forwarded-For Keep-Alive test
50 @echo starting apache ..
51 @$(HTTPD) -D test6 &
52 @./run_test.pl test6
53 @echo stopping apache ..
54 @kill -HUP `cat httpd.pid`
55 @rm httpd.pid
56 @echo test 7 - X-Forwarded-For Keep-Alive test with HostNameLookups On
57 @echo starting apache ..
58 @$(HTTPD) -D test7 &
59 @./run_test.pl test7
60 @echo stopping apache ..
61 @kill -HUP `cat httpd.pid`
62 @rm httpd.pid
63
64 test-2.0:
65 rm -f rpaf-error_log rpaf-access_log
66 @echo running rpaf apache 2.x.x tests
67 @echo test 1 - no rpaf
68 @echo starting apache ..
69 @$(HTTPD2) -D test1 &
70 @./run_test.pl test1
71 @echo stopping apache ..
72 @kill -9 `cat httpd.pid`
73 @rm httpd.pid
74 @echo test 2 - rpaf enabled
75 @echo starting apache ..
76 @$(HTTPD2) -D test2 &
77 @./run_test.pl test2
78 @echo stopping apache ..
79 @kill -9 `cat httpd.pid`
80 @rm httpd.pid
81 @echo test 3 - rpaf enabled - sethostname enabled
82 @echo starting apache ..
83 @$(HTTPD2) -D test3 &
84 @./run_test.pl test3
85 @echo stopping apache ..
86 @kill -9 `cat httpd.pid`
87 @rm httpd.pid
88 @echo test 4 - rpaf enabled - sethostname enabled - specifying header
89 @echo setting X-Forwarded-For
90 @echo starting apache ..
91 @$(HTTPD2) -D test4 &
92 @./run_test.pl test4
93 @echo stopping apache ..
94 @kill -9 `cat httpd.pid`
95 @rm httpd.pid
96 @echo test 5 - rpaf enabled - sethostname enabled - specifying header
97 @echo setting X-Real-IP
98 @echo starting apache ..
99 @$(HTTPD2) -D test5 &
100 @./run_test.pl test5
101 @echo stopping apache ..
102 @kill -9 `cat httpd.pid`
103 @rm httpd.pid
104 @echo test 6 - X-Forwarded-For Keep-Alive test
105 @echo starting apache ..
106 @$(HTTPD2) -D test6 &
107 @./run_test.pl test6
108 @echo stopping apache ..
109 @kill -9 `cat httpd.pid`
110 @rm httpd.pid
111 @echo test 7 - X-Forwarded-For Keep-Alive test with HostNameLookups On
112 @echo starting apache ..
113 @$(HTTPD2) -D test7 &
114 @./run_test.pl test7
115 @echo stopping apache ..
116 @kill -9 `cat httpd.pid`
117 @rm httpd.pid
118
119 clean:
120 rm -rf httpd.pid rpaf-access_log rpaf-error_log httpd-rpaf.conf httpd-rpaf.conf-2.0 Makefile