convert "::1" and other pseudo-IPv6 addresses that Apache may throw at us to their IPv4 counterparts
This commit is contained in:
parent
7c21394c41
commit
fd989dcea6
2 changed files with 37 additions and 3 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
Loading…
Reference in a new issue