return C4::Context->config('tmp_path') || File::Spec->tmpdir;
}
+=head3 set_remote_address
+
+set_remote_address should be called at the beginning of every script
+that is *not* running under plack in order to the REMOTE_ADDR environment
+variable to be set correctly.
+
+=cut
+
+sub set_remote_address {
+ if ( C4::Context->config('koha_trusted_proxies') ) {
+ require CGI;
+ my $cgi = CGI->new;
+ my $header = $cgi->http('HTTP_X_FORWARDED_FOR');
+
+ if ($header) {
+ require Koha::Middleware::RealIP;
+ $ENV{REMOTE_ADDR} = Koha::Middleware::RealIP::get_real_ip( $ENV{REMOTE_ADDR}, $header );
+ }
+ }
+}
1;
--- /dev/null
+package Koha::Middleware::RealIP;
+
+# Copyright 2019 ByWater Solutions and the Koha Dev Team
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use parent qw(Plack::Middleware);
+
+use C4::Context;
+
+use Net::Netmask;
+use Plack::Util::Accessor qw( trusted_proxy );
+
+=head1 METHODS
+
+=head2 prepare_app
+
+This method generates and stores the list of trusted ip's as Netmask objects
+at the time Plack starts up, obviating the need to regerenate them on each request.
+
+=cut
+
+sub prepare_app {
+ my $self = shift;
+ $self->trusted_proxy( get_trusted_proxies() );
+}
+
+=head2 call
+
+This method is called for each request, and will ensure the correct remote address
+is set in the REMOTE_ADDR environment variable.
+
+=cut
+
+sub call {
+ my $self = shift;
+ my $env = shift;
+
+ if ( $env->{HTTP_X_FORWARDED_FOR} ) {
+ my @trusted_proxy = $self->trusted_proxy ? @{ $self->trusted_proxy } : undef;
+
+ if (@trusted_proxy) {
+ my $addr = get_real_ip( $env->{REMOTE_ADDR}, $env->{HTTP_X_FORWARDED_FOR}, \@trusted_proxy );
+ $ENV{REMOTE_ADDR} = $addr;
+ $env->{REMOTE_ADDR} = $addr;
+ }
+ }
+
+ return $self->app->($env);
+}
+
+=head2 get_real_ip
+
+my $address = get_real_ip( $remote_addres, $x_forwarded_for_header );
+
+This method takes the current remote address and the x-forwarded-for header string,
+determines the correct external ip address, and returns it.
+
+=cut
+
+sub get_real_ip {
+ my ( $remote_addr, $header ) = @_;
+
+ my @forwarded_for = $header =~ /([^,\s]+)/g;
+ return $remote_addr unless @forwarded_for;
+
+ my $trusted_proxies = get_trusted_proxies();
+
+ my @unconfirmed = ( @forwarded_for, $remote_addr );
+
+ my $real_ip;
+ while (my $addr = pop @unconfirmed) {
+ my $has_matched = 0;
+ foreach my $netmask (@$trusted_proxies) {
+ $has_matched++, last if $netmask->match($addr);
+ }
+ $real_ip = $addr, last unless $has_matched;
+ }
+
+ return $real_ip;
+}
+
+=head2 get_trusted_proxies
+
+This method returns an arrayref of Net::Netmask objects for all
+the trusted proxies given to Koha.
+
+=cut
+
+sub get_trusted_proxies {
+ my $proxies_conf = C4::Context->config('koha_trusted_proxies');
+ return unless $proxies_conf;
+ my @trusted_proxies_ip = split( / /, $proxies_conf );
+ my @trusted_proxies = map { Net::Netmask->new($_) } @trusted_proxies_ip;
+ return \@trusted_proxies;
+}
+
+
+=head1 AUTHORS
+
+Kyle M Hall <kyle@bywatersolutions.com>
+
+=cut
+
+1;