]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1217536 - allow inbound_proxy supports '*'
authorDylan William Hardison <dylan@hardison.net>
Wed, 28 Oct 2015 02:27:34 +0000 (22:27 -0400)
committerDylan William Hardison <dylan@hardison.net>
Wed, 28 Oct 2015 02:28:03 +0000 (22:28 -0400)
Bugzilla/Config/Advanced.pm
Bugzilla/Config/Common.pm
Bugzilla/Util.pm
t/013remote_ip.t [new file with mode: 0644]
template/en/default/admin/params/advanced.html.tmpl

index 4b57df24d84daabd0beada64934ef55f213e6d63..893213b027c91718937e520e213e5b447cf5cf92 100644 (file)
@@ -47,7 +47,7 @@ use constant get_param_list => (
    name => 'inbound_proxies',
    type => 't',
    default => '',
-   checker => \&check_ip
+   checker => \&check_inbound_proxies
   },
 
   {
@@ -108,4 +108,15 @@ use constant get_param_list => (
   },
 );
 
+sub check_inbound_proxies {
+    my $inbound_proxies = shift;
+
+    return "" if $inbound_proxies eq "*";
+    my @proxies = split(/[\s,]+/, $inbound_proxies);
+    foreach my $proxy (@proxies) {
+        validate_ip($proxy) || return "$proxy is not a valid IPv4 or IPv6 address";
+    }
+    return "";
+}
+
 1;
index 35a70994bb6e26b00d24e464eb3330c08eda6c0b..4c9994e0e73a39e44cf581a636d80caf9af1d05f 100644 (file)
@@ -48,7 +48,7 @@ use base qw(Exporter);
     qw(check_multi check_numeric check_regexp check_url check_group
        check_sslbase check_priority check_severity check_platform
        check_opsys check_shadowdb check_urlbase check_webdotbase
-       check_user_verify_class check_ip
+       check_user_verify_class
        check_mail_delivery_method check_notification check_utf8
        check_bug_status check_smtp_auth check_theschwartz_available
        check_maxattachmentsize check_email
@@ -130,15 +130,6 @@ sub check_sslbase {
     return "";
 }
 
-sub check_ip {
-    my $inbound_proxies = shift;
-    my @proxies = split(/[\s,]+/, $inbound_proxies);
-    foreach my $proxy (@proxies) {
-        validate_ip($proxy) || return "$proxy is not a valid IPv4 or IPv6 address";
-    }
-    return "";
-}
-
 sub check_utf8 {
     my $utf8 = shift;
     # You cannot turn off the UTF-8 parameter if you've already converted
index d80ab956955286f8baa574dbfa22352b0fb82181..f793ed727116ae9a1af5947895168b0fe7ba8a4f 100644 (file)
@@ -57,7 +57,7 @@ use DateTime;
 use DateTime::TimeZone;
 use Digest;
 use Email::Address;
-use List::Util qw(first);
+use List::MoreUtils qw(none);
 use Scalar::Util qw(tainted blessed);
 use Text::Wrap;
 use Encode qw(encode decode resolve_alias);
@@ -305,28 +305,23 @@ sub correct_urlbase {
     }
 }
 
+# Returns the real remote address of the client,
 sub remote_ip {
-    my $ip = $ENV{'REMOTE_ADDR'} || '127.0.0.1';
-    my @proxies = split(/[\s,]+/, Bugzilla->params->{'inbound_proxies'});
-
-    # If the IP address is one of our trusted proxies, then we look at
-    # the X-Forwarded-For header to determine the real remote IP address.
-    if ($ENV{'HTTP_X_FORWARDED_FOR'} && first { $_ eq $ip } @proxies) {
-        my @ips = split(/[\s,]+/, $ENV{'HTTP_X_FORWARDED_FOR'});
-        # This header can contain several IP addresses. We want the
-        # IP address of the machine which connected to our proxies as
-        # all other IP addresses may be fake or internal ones.
-        # Note that this may block a whole external proxy, but we have
-        # no way to determine if this proxy is malicious or trustable.
-        foreach my $remote_ip (reverse @ips) {
-            if (!first { $_ eq $remote_ip } @proxies) {
-                # Keep the original IP address if the remote IP is invalid.
-                $ip = validate_ip($remote_ip) || $ip;
-                last;
-            }
+    my $remote_ip       = $ENV{'REMOTE_ADDR'} || '127.0.0.1';
+    my @proxies         = split(/[\s,]+/, Bugzilla->params->{inbound_proxies});
+    my @x_forwarded_for = split(/[\s,]+/, $ENV{HTTP_X_FORWARDED_FOR} // '');
+
+    return $remote_ip unless @x_forwarded_for;
+    return $x_forwarded_for[0] if $proxies[0] eq '*';
+    return $remote_ip if none { $_ eq $remote_ip } @proxies;
+
+    foreach my $ip (reverse @x_forwarded_for) {
+        if (none { $_ eq $ip } @proxies) {
+            # Keep the original IP address if the remote IP is invalid.
+            return validate_ip($ip) || $remote_ip;
         }
     }
-    return $ip;
+    return $remote_ip;
 }
 
 sub validate_ip {
diff --git a/t/013remote_ip.t b/t/013remote_ip.t
new file mode 100644 (file)
index 0000000..1cc832a
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/perl
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+use strict;
+use lib qw(. lib t);
+use Test::More qw(no_plan);
+use Bugzilla;
+use Bugzilla::Util qw(remote_ip);
+
+my $params = Bugzilla->params;
+
+{
+    local $params->{inbound_proxies} = '10.0.0.1,10.0.0.2';
+    local $ENV{REMOTE_ADDR} = '10.0.0.2';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '10.42.42.42';
+
+    is(remote_ip(), '10.42.42.42', "from proxy 2");
+}
+
+{
+    local $params->{inbound_proxies} = '10.0.0.1,10.0.0.2';
+    local $ENV{REMOTE_ADDR} = '10.0.0.1';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '10.42.42.42';
+
+    is(remote_ip(), '10.42.42.42', "from proxy 1");
+}
+
+{
+    local $params->{inbound_proxies} = '10.0.0.1,10.0.0.2';
+    local $ENV{REMOTE_ADDR} = '10.0.0.3';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '10.42.42.42';
+
+    is(remote_ip(), '10.0.0.3', "not a proxy");
+}
+
+{
+    local $params->{inbound_proxies} = '*';
+    local $ENV{REMOTE_ADDR} = '10.0.0.3';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '10.42.42.42,1.4.9.2';
+
+    is(remote_ip(), '10.42.42.42', "always proxy");
+}
+
+{
+    local $params->{inbound_proxies} = '';
+    local $ENV{REMOTE_ADDR} = '10.9.8.7';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '10.42.42.42,1.4.9.2';
+
+    is(remote_ip(), '10.9.8.7', "never proxy");
+}
+
+
+{
+    local $params->{inbound_proxies} = '10.0.0.1,2600:cafe::cafe:ffff:bf42:4998';
+    local $ENV{REMOTE_ADDR} = '2600:cafe::cafe:ffff:bf42:4998';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '2600:cafe::cafe:ffff:bf42:BEEF';
+
+    is(remote_ip(), '2600:cafe::cafe:ffff:bf42:BEEF', "from proxy ipv6");
+}
+
+{
+    local $params->{inbound_proxies} = '10.0.0.1,2600:cafe::cafe:ffff:bf42:4998';
+    local $ENV{REMOTE_ADDR} = '2600:cafe::cafe:ffff:bf42:DEAD';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '2600:cafe::cafe:ffff:bf42:BEEF';
+
+    is(remote_ip(), '2600:cafe::cafe:ffff:bf42:DEAD', "invalid proxy ipv6");
+}
+
+
+{
+    local $params->{inbound_proxies} = '*';
+    local $ENV{REMOTE_ADDR} = '2600:cafe::cafe:ffff:bf42:DEAD';
+    local $ENV{HTTP_X_FORWARDED_FOR} = '';
+
+    is(remote_ip(), '2600:cafe::cafe:ffff:bf42:DEAD', "always proxy ipv6");
+}
index a2103c652cf8d6b70eec610fff1d0d3d84d99d78..6cd13a49d930f263545f4dce7a2e5aa411695846 100644 (file)
@@ -67,7 +67,9 @@
     _ " user is the IP address of the proxy. If you enter a comma-separated"
     _ " list of IPs in this parameter, then $terms.Bugzilla will trust any"
     _ " <code>X-Forwarded-For</code> header sent from those IPs,"
-    _ " and use the value of that header as the end user's IP address.",
+    _ " and use the value of that header as the end user's IP address."
+    _ " If set to a *, $terms.Bugzilla will trust the first value in the "
+    _ " X-Forwarded-For header.",
 
   proxy_url => 
     "$terms.Bugzilla may have to access the web to get notifications about"