mourningdove/cgi-bin/Plack/Middleware/DW/XForwardedFor.pm

69 lines
2 KiB
Perl
Raw Normal View History

2026-05-24 01:03:05 +00:00
#!/usr/bin/perl
#
# Plack::Middleware::DW::XForwardedFor
#
# Sets up IP address based on proxy trust.
#
# Authors:
# Mark Smith <mark@dreamwidth.org>
#
# Copyright (c) 2021 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself. For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#
package Plack::Middleware::DW::XForwardedFor;
use strict;
use v5.10;
use Log::Log4perl;
my $log = Log::Log4perl->get_logger(__PACKAGE__);
use parent qw/ Plack::Middleware /;
sub call {
my ( $self, $env ) = @_;
return $self->app->($env)
unless $LJ::TRUST_X_HEADERS;
my $r = DW::Request->get;
# Assume user's IP comes in the real IP, but if not, we need to grab it out of
# the X-Forwarded-For -- respecting IS_TRUSTED_PROXY
if ( my $forward = $r->header_in('X-Forwarded-For') ) {
my @hosts = split( /\s*,\s*/, $forward );
if (@hosts) {
my $real;
if ( ref $LJ::IS_TRUSTED_PROXY eq 'CODE' ) {
# Find last IP in X-Forwarded-For that isn't a trusted proxy.
do {
$real = pop @hosts;
} while ( @hosts && $LJ::IS_TRUSTED_PROXY->($real) );
}
else {
# Trust everything by default, real client IP is first.
$real = shift @hosts;
@hosts = ();
}
$r->address($real);
# Also update the PSGI env so infrastructure that reads it
# directly (Starman access log, Sysban, etc.) sees the real IP.
$env->{REMOTE_ADDR} = $real;
}
$r->header_in( 'X-Forwarded-For' => join( ", ", @hosts ) );
}
# and now, deal with getting the right Host header
my $host = $r->header_in('X-Host') // $r->header_in('X-Forwarded-Host');
$r->header_in( 'Host' => $host ) if defined $host;
return $self->app->($env);
}
1;