[interchange] Enhance TrustProxy to handle multiple chained proxies
Jon Jensen
interchange-cvs at icdevgroup.org
Sat Apr 2 19:18:38 UTC 2011
commit 29c73e67feb9240bca3a60288cad7d7293f482c9
Author: Jon Jensen <jon at endpoint.com>
Date: Thu Mar 31 22:24:07 2011 -0500
Enhance TrustProxy to handle multiple chained proxies
This can happen if, for example, you have a first proxy at 10.10.10.1
which proxies to 10.10.10.2 which then hits your web server that passes
control to Interchange.
If you visit from 192.168.1.1, Interchange will see this HTTP header:
X-Forwarded-For: 192.168.1.1, 10.10.10.1
and the request will have the source IP address 10.10.10.2.
But if you set this in interchange.cfg:
TrustProxy 10.10.10.1, 10.10.10.2 # order irrelevant
then Interchange will see past the two trusted proxies and set its
standard variable $CGI::remote_addr to 192.168.1.1, so that the customer's
IP address gets used.
lib/Vend/Server.pm | 47 +++++++++++++++++++++++++++++------------------
1 files changed, 29 insertions(+), 18 deletions(-)
---
diff --git a/lib/Vend/Server.pm b/lib/Vend/Server.pm
index 7305cec..a6620f5 100644
--- a/lib/Vend/Server.pm
+++ b/lib/Vend/Server.pm
@@ -127,26 +127,37 @@ sub populate {
# try to get originating host's IP address if request was
# forwarded through a trusted proxy
- my $ip;
- if ($Global::TrustProxy
- and ($CGI::remote_addr =~ $Global::TrustProxy
- or $CGI::remote_host =~ $Global::TrustProxy)
- and $ip = $cgivar->{HTTP_X_FORWARDED_FOR}) {
- # trust only the last hop's IP address before our trusted proxy
- # when multiples are present in a comma-separated list
- $ip =~ s/.*,//;
- $ip =~ s/^\s+//; $ip =~ s/\s+$//;
- if ($ip =~ /^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$/) {
+ if (
+ $Global::TrustProxy
+ and (
+ $CGI::remote_addr =~ $Global::TrustProxy
+ or $CGI::remote_host =~ $Global::TrustProxy
+ )
+ and my $forwarded_for = $cgivar->{HTTP_X_FORWARDED_FOR}
+ ) {
+ # multiple source IP addresses may appear in X-Forwarded-For header
+ # in a comma-separated list
+ for my $ip (reverse grep /\S/, split /\s*,\s*/, $forwarded_for) {
+ # do we have a valid-looking IP address?
+ if ($ip !~ /^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$/) {
+ # if not, log error and ignore X-Forwarded-For header
+ ::logGlobal(
+ { level => 'info' },
+ "Unknown X-Forwarded-For header set from trusted proxy %s: %s",
+ $CGI::remote_addr,
+ $forwarded_for,
+ );
+ last;
+ }
+
+ # skip any other upstream trusted proxies
+ next if $ip =~ $Global::TrustProxy;
+
+ # rightmost IP address that's not a trusted proxy is the customer IP
+ # address as far as we're concerned, so keep that and exit loop
$CGI::remote_addr = $ip;
undef $CGI::remote_host;
- }
- else {
- ::logGlobal(
- { level => 'info' },
- "Unknown HTTP_X_FORWARDED_FOR header set from trusted proxy %s: '%s'",
- $CGI::remote_addr,
- $cgivar->{HTTP_X_FORWARDED_FOR},
- );
+ last;
}
}
}
More information about the interchange-cvs
mailing list