From: Ilmari Karonen Date: Wed, 29 Nov 2006 08:08:57 +0000 (+0000) Subject: convert "::1" and other pseudo-IPv6 addresses that Apache may throw at us to their... X-Git-Tag: 1.31.0-rc.0~55044 X-Git-Url: http://git.cyclocoop.org/%24href?a=commitdiff_plain;h=fd989dcea69ffc13554482b5a3a994c4b457c194;p=lhc%2Fweb%2Fwiklou.git convert "::1" and other pseudo-IPv6 addresses that Apache may throw at us to their IPv4 counterparts --- diff --git a/includes/IP.php b/includes/IP.php index 14addb9496..713780432d 100644 --- a/includes/IP.php +++ b/includes/IP.php @@ -10,11 +10,15 @@ // Some regex definition to "play" with IP address and IP address blocks // An IP is made of 4 bytes from x00 to xFF which is d0 to d255 -define( 'RE_IP_BYTE', '(25[0-5]|2[0-4]\d|1?\d{1,2})'); +define( 'RE_IP_BYTE', '(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)'); define( 'RE_IP_ADD' , RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE ); // An IP block is an IP address and a prefix (d1 to d32) -define( 'RE_IP_PREFIX' , '(3[0-2]|[12]?\d)'); +define( 'RE_IP_PREFIX', '(3[0-2]|[12]?\d)'); define( 'RE_IP_BLOCK', RE_IP_ADD . '\/' . RE_IP_PREFIX); +// For IPv6 canonicalization (NOT for strict validation; these are quite lax!) +define( 'RE_IPV6_WORD', '([0-9A-Fa-f]{1,4})' ); +define( 'RE_IPV6_GAP', ':(?:0+:)*(?::(?:0+:)*)?' ); +define( 'RE_IPV6_V4_PREFIX', '0*' . RE_IPV6_GAP . '(?:ffff:)?' ); class IP { @@ -220,5 +224,33 @@ class IP { return (($unsignedIP >= $start) && ($unsignedIP <= $end)); } + + /** + * Convert some unusual representations of IPv4 addresses to their + * canonical dotted quad representation. + * + * This currently only checks a few IPV4-to-IPv6 related cases. More + * unusual representations may be added later. + * + * @param $addr something that might be an IP address + * @return valid dotted quad IPv4 address or null + */ + public static function canonicalize( $addr ) { + if ( IP::isValid( $addr ) ) + return $addr; + + // IPv6 loopback address + if ( preg_match( '/^0*' . RE_IPV6_GAP . '1$/', $addr, $m ) ) + return '127.0.0.1'; + + // IPv4-mapped and IPv4-compatible IPv6 addresses + if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . '(' . RE_IP_ADD . ')$/i', $addr, $m ) ) + return $m[1]; + if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . RE_IPV6_WORD . ':' . RE_IPV6_WORD . '$/i', $addr, $m ) ) + return long2ip( ( hexdec( $m[1] ) << 16 ) + hexdec( $m[2] ) ); + + return null; // give up + } } + ?> diff --git a/includes/ProxyTools.php b/includes/ProxyTools.php index 1b65406d95..22ea4947cb 100644 --- a/includes/ProxyTools.php +++ b/includes/ProxyTools.php @@ -33,7 +33,7 @@ function wfGetIP() { /* collect the originating ips */ # Client connecting to this webserver if ( isset( $_SERVER['REMOTE_ADDR'] ) ) { - $ipchain = array( $_SERVER['REMOTE_ADDR'] ); + $ipchain = array( IP::canonicalize( $_SERVER['REMOTE_ADDR'] ) ); } else { # Running on CLI? $ipchain = array( '127.0.0.1' ); @@ -47,9 +47,11 @@ function wfGetIP() { $xff = array_reverse( $xff ); $ipchain = array_merge( $ipchain, $xff ); } + # 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 ) { + $curIP = IP::canonicalize( $curIP ); if ( wfIsTrustedProxy( $curIP ) ) { if ( isset( $ipchain[$i + 1] ) && IP::isPublic( $ipchain[$i + 1] ) ) { $ip = $ipchain[$i + 1];