12.9 Getting the Remote Server IP in the Backend Server in the Proxy Setup

When using the proxy setup to boost performance, you might face the problem that the remote IP always seems to be 127.0.0.1, which is your proxy's IP. To solve that issue, Ask Bjoern Hansen has written the mod_proxy_add_forward module,[3] which can be aded to the frontend Apache server. It sets the X-Forwarded-For header when doing a ProxyPass, similar to what Squid can do. This header contains the IP address of the client connecting to the proxy, which you can then access in the mod_perl-enabled server. You won't need to compile anything into the backend server.

[3] See Section 12.16 at the end of this chapter for download information.

To enable this module you have to recompile the frontend server with the following options:

panic% ./configure \
     --with-layout=Apache \
     --activate-module=src/modules/extra/mod_proxy_add_forward.c \
     --enable-module=proxy_add_forward \
     ... other options ...

Adjust the location of mod_proxy_add_forward.c if needed.

In the backend server you can use the handler in Example 12-4 to automatically correct $r->connection->remote_ip.

Example 12-4. Book/ProxyRemoteAddr.pm
package Book::ProxyRemoteAddr;

use Apache::Constants qw(OK);
use strict;

sub handler {
    my $r = shift;

    # we'll only look at the X-Forwarded-For header if the request
    # comes from our proxy at localhost
    return OK unless ($r->connection->remote_ip eq "127.0.0.1") &&
        $r->header_in('X-Forwarded-For');

    # Select last value in the chain -- original client's IP
    if (my ($ip) = $r->headers_in->{'X-Forwarded-For'} =~ /([^,\s]+)$/) {
        $r->connection->remote_ip($ip);
    }

    return OK;
}
1;

Next, enable this handler in the backend's httpd.conf file:

PerlPostReadRequestHandler Book::ProxyRemoteAddr

and the right thing will happen transparently for your scripts: for Apache::Registry or Apache::PerlRun scripts, you can access the remote IP through $ENV{REMOTE_ADDR}, and for other handlers you can use $r->connection->remote_ip.

Generally, you shouldn't trust the X-Forwarded-For header. You should only rely on the X-Forwarded-For header from proxies you control yourself?this is why the recommended handler we have just presented checks whether the request really came from 127.0.0.1 before changing remote_ip. If you know how to spoof a cookie, you've probably got the general idea of making HTTP headers and can spoof the X-Forwarded-For header as well. The only address you can count on as being a reliable value is the one from $r->connection->remote_ip.



    Part I: mod_perl Administration
    Part II: mod_perl Performance
    Part VI: Appendixes