/* ==================================================================== * "THE FOO LICENSE" (Revision 3.14159265358979323844): * * wrote this file. As long as you retain this * notice you can do whatever you want with this stuff. If it does * anything you didn't want it to do, it is of course your own fault. * If we meet some day, and you think this stuff is worth it, you * can buy me a beer in return. - Ask Bjoern Hansen. * * ==================================================================== */ /* proxy_add_forward module * * This module adds a 'X-Forwarded-For' header to outgoing * proxy requests like Squid does. * * You can then get the client ip back on the "proxied host" by * setting r->connection->remote_ip from this header. * * Ask Bjoern Hansen , October 1998 * Changes: * * July 10th, 2002: More documentation info, thanks to Stas Bekman * * .... * * February 1st 2001: Added X-Host and X-Server-Name forwarding. * * January 15 2001: Fixed the copyright to not be ASF's since I never * got around to put this into mod_perl. * * April 12 2000: Changed the license to the ASF 1.1 license. * * April 12 2000: Made it so that we append our IP to an existing * "X-Forwarded-For" line instead of clobbering an * existing one. - * * June 8 1999: Added instructions on how to compile it into the * frontend apache * * April 12 1999: Changed the sample code so it doesn't confuse the * C compiler, ydkhr! Thanks to Mike Whitaker for * noticing. * * March 1 1999: Added sample code on how to use the header with * mod_perl * To use the module you have to compile it into the frontend part of your server, I usually copy the module to apache-1.3/src/modules/extra/ and use APACI like: ./configure --prefix=/usr/local/apache \ --activate-module=src/modules/extra/mod_proxy_add_forward.c \ --enable-module=proxy_add_forward [... more apaci options ...] You should also be able to compile and use this module as a dynamically loaded module (DSO). TMTOWTDI, but I usually make the 'backend' part of the system something like the following: in startup.pl: sub My::ProxyRemoteAddr ($) { my $r = shift; # we'll only look at the X-Forwarded-For header if the requests # comes from our proxy at localhost return OK unless ($r->connection->remote_ip eq "127.0.0.1"); if (my ($ip) = $r->header_in('X-Forwarded-For') =~ /([^,\s]+)$/) { $r->connection->remote_ip($ip); } return OK; } And in httpd.conf: PerlPostReadRequestHandler My::ProxyRemoteAddr =head2 mod_proxy_add_forward Module's Order Precedence Some users report that they cannot get this module to work as advertised. They verify that the module is built in, but the front-end server is not generating the C header when requests are being proxied to the back-end server. As a result, the back-end server has no idea what the remote IP is. As it turns out, I needs to be configured in Apache before I in order to operate properly, since Apache gives highest precedence to the last defined module. Moving the two build options required to enable I while configuring Apache appears to have no effect on the default configuration order of modules, since in each case, the resulting builds show I last in the list (or first via I). One solution is to explicitly define the configuration order in the I file, so that I appears before I, and therefore gets executed after I. (Modules are being executed in I order, i.e. module that was I first will be executed last.) Obviously, this list would need to be tailored to match the build environment, but to ease this task just insert an C directive before each entry reported by C (and removing I): ClearModuleList AddModule mod_env.c [more modules snipped] AddModule mod_proxy_add_forward.c AddModule mod_proxy.c AddModule mod_rewrite.c AddModule mod_setenvif.c Note that the above snippet is added to I of the front-end server. Another solution is to reorder the module list during configuration by using one or more C<--permute-module> arguments to the I<./configure> utility. (Try C<./configure --help> to see if your version of Apache supports this option.) C<--permute-module=foo:bar> will swap the position of I and I in the list, C<--permute-module=BEGIN:foo> will move I to the beginning of the list, and C<--permute-module=foo:END> will move I to the end. For example suppose your module list from C looks like: http_core.c [more modules snipped] mod_proxy.c mod_setenvif.c mod_proxy_add_forward.c You might add the following arguments to I<./configure> to move I to the position in the list just before I: panic% ./configure \ "--with-layout=Apache" \ "--activate-module=src/modules/extra/mod_proxy_add_forward.c" \ "--enable-module=proxy_add_forward" \ ... other options ... "--permute-module=proxy:proxy_add_forward" \ "--permute-module=setenvif:END" With this change, the C header is now being sent to the back-end server, and the remote IP appears in the back-end server's I file. */ #include "httpd.h" #include "http_config.h" #include "http_core.h" module MODULE_VAR_EXPORT proxy_add_forward_module; static int add_forward_header(request_rec *r) { const char *oldvalue; if (r->proxyreq) { /* If there is an existing header, append our IP to that. */ if (oldvalue = ap_table_get(r->headers_in, "X-Forwarded-For")) { ap_table_set(r->headers_in, "X-Forwarded-For", ap_pstrcat(r->pool, oldvalue, ", ", r->connection->remote_ip, NULL)); } else { ap_table_set(r->headers_in, "X-Forwarded-For", r->connection->remote_ip); } ap_table_set(r->headers_in, "X-Host", ap_table_get(r->headers_in, "Host")); ap_table_set(r->headers_in, "X-Server-Hostname", r->server->server_hostname); return OK; } return DECLINED; } module MODULE_VAR_EXPORT proxy_add_forward_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server configs */ NULL, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ add_forward_header, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ };