Adding some validation for IP determination via XFF headers, in preparation for addin...
authorTim Starling <tstarling@users.mediawiki.org>
Thu, 31 Mar 2005 09:10:25 +0000 (09:10 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Thu, 31 Mar 2005 09:10:25 +0000 (09:10 +0000)
includes/ProxyTools.php [new file with mode: 0644]
includes/Setup.php

diff --git a/includes/ProxyTools.php b/includes/ProxyTools.php
new file mode 100644 (file)
index 0000000..d335fae
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+       die();
+}
+
+/**
+ * Functions for dealing with proxies
+ */
+
+
+/**
+ * Work out the IP address based on various globals
+ */
+function wfGetIP()
+{
+       global $wgSquidServers, $wgSquidServersNoPurge;
+
+       /* collect the originating ips */
+       # Client connecting to this webserver
+       if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
+               $ipchain = array( $_SERVER['REMOTE_ADDR'] );
+       } else {
+               # Running on CLI?
+               $ipchain = array( '127.0.0.1' );
+       }
+       $ip = $ipchain[0];
+
+       # Get list of trusted proxies
+       # Flipped for quicker access
+       $trustedProxies = array_flip( array_merge( $wgSquidServers, $wgSquidServersNoPurge ) );
+       if ( count( $trustedProxies ) ) {
+               # Append XFF on to $ipchain
+               if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
+                       $ipchain = array_merge( $ipchain, array_map( 'trim', explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) );
+               }
+               # Step through XFF list and find the last address in the list which is a trusted server
+               # Set $ip to the IP address given by that trusted server, unless the address is not sensible (e.g. private)
+               foreach ( $ipchain as $i => $curIP ) {
+                       if ( array_key_exists( $curIP, $trustedProxies ) ) {
+                               if ( isset( $ipchain[$i + 1] ) && wfIsIPPublic( $ipchain[$i + 1] ) ) {
+                                       $ip = $ipchain[$i + 1];
+                               }
+                       } else {
+                               break;
+                       }
+               }
+       }
+
+       return $ip;
+}
+
+function wfIP2Unsigned( $ip )
+{
+       $n = ip2long( $ip );
+       if ( $n == -1 ) {
+               $n = false;
+       } elseif ( $n < 0 ) {
+               $n += pow( 2, 32 );
+       }
+       return $n;
+}
+
+/**
+ * Determine if an IP address really is an IP address, and if it is public, 
+ * i.e. not RFC 1918 or similar
+ */
+function wfIsIPPublic( $ip )
+{
+       $n = wfIP2Unsigned( $ip );
+       if ( !$n ) {
+               return false;
+       }
+
+       static $privateRanges = false;
+       if ( !$privateRanges ) {
+               $privateRanges = array(
+                       array( '10.0.0.0',    '10.255.255.255' ),   # RFC 1918 (private)
+                       array( '172.16.0.0',  '172.31.255.255' ),   #     "
+                       array( '192.168.0.0', '192.168.255.255' ),  #     "
+                       array( '0.0.0.0',     '0.255.255.255' ),    # this network
+                       array( '127.0.0.0',   '127.255.255.255' ),  # loopback
+               );
+       }
+
+       foreach ( $privateRanges as $r ) {
+               $start = wfIP2Unsigned( $r[0] );
+               $end = wfIP2Unsigned( $r[1] );
+               if ( $n >= $start && $n <= $end ) {
+                       return false;
+               }
+       }
+       return true;
+}
+       
+?>
index c615667..bfbe0c7 100644 (file)
@@ -16,7 +16,7 @@ if( defined( 'MEDIAWIKI' ) ) {
 # setting up a few globals.
 #
 
-global $wgProfiling, $wgProfileSampleRate, $wgIP, $wgUseSquid, $IP;
+global $wgProfiling, $wgProfileSampleRate, $wgIP, $IP;
 
 if( !isset( $wgProfiling ) )
        $wgProfiling = false;
@@ -41,26 +41,6 @@ if ( $wgProfiling and (0 == rand() % $wgProfileSampleRate ) ) {
         function wfProfileClose() {}
 }
 
-
-
-/* collect the originating ips */
-if( $wgUseSquid && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
-       # If the web server is behind a reverse proxy, we need to find
-       # out where our requests are really coming from.
-       $hopips = array_map( 'trim', explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
-
-       $allsquids = array_merge($wgSquidServers, $wgSquidServersNoPurge);
-       while(in_array(trim(end($hopips)), $allsquids)){
-               array_pop($hopips);
-       }
-       $wgIP = trim(end($hopips));
-} elseif( isset( $_SERVER['REMOTE_ADDR'] ) ) {
-       $wgIP = $_SERVER['REMOTE_ADDR'];
-} else {
-       # Running on CLI?
-       $wgIP = '127.0.0.1';
-}
-
 $fname = 'Setup.php';
 wfProfileIn( $fname );
 global $wgUseDynamicDates;
@@ -87,8 +67,6 @@ require_once( 'WebRequest.php' );
 require_once( 'LoadBalancer.php' );
 require_once( 'HistoryBlob.php' );
 
-$wgRequest = new WebRequest();
-
 wfProfileOut( $fname.'-includes' );
 wfProfileIn( $fname.'-misc1' );
 global $wgUser, $wgLang, $wgContLang, $wgOut, $wgTitle;
@@ -104,6 +82,9 @@ global $wgUseOldExistenceCheck, $wgEnablePersistentLC, $wgMasterWaitTimeout;
 
 global $wgFullyInitialised;
 
+$wgIP = wfGetIP();
+$wgRequest = new WebRequest();
+
 # Useful debug output
 if ( $wgCommandLineMode ) {
        # wfDebug( '"' . implode( '"  "', $argv ) . '"' );