Make 'subnet' feature of $wgRateLimits work with IPv6
authorAlexandre Emsenhuber <ialex.wiki@gmail.com>
Thu, 16 May 2013 06:19:13 +0000 (08:19 +0200)
committerAlexandre Emsenhuber <ialex.wiki@gmail.com>
Thu, 16 May 2013 06:19:13 +0000 (08:19 +0200)
- 'subnet' will aggregate limits for a /64 subnet on IPv6
- Updated DefaultSettings.php to mention this
- Only call WebRequest::getIP() when it will really be used

Change-Id: Ia96800df5fb498a79e2c0527baee2392cd4623c7

includes/DefaultSettings.php
includes/User.php

index 296b71d..2c03f13 100644 (file)
@@ -4328,7 +4328,7 @@ $wgRateLimits = array(
                'user' => null, // for each logged-in user
                'newbie' => null, // for each recent (autoconfirmed) account; overrides 'user'
                'ip' => null, // for each anon and recent account
-               'subnet' => null, // ... with final octet removed
+               'subnet' => null, // ... within a /24 subnet in IPv4 or /64 in IPv6
        ),
        'move' => array(
                'user' => null,
index d114b99..617336d 100644 (file)
@@ -1500,7 +1500,6 @@ class User {
                $limits = $wgRateLimits[$action];
                $keys = array();
                $id = $this->getId();
-               $ip = $this->getRequest()->getIP();
                $userLimit = false;
 
                if ( isset( $limits['anon'] ) && $id == 0 ) {
@@ -1515,12 +1514,23 @@ class User {
                                $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
                        }
                        if ( isset( $limits['ip'] ) ) {
+                               $ip = $this->getRequest()->getIP();
                                $keys["mediawiki:limiter:$action:ip:$ip"] = $limits['ip'];
                        }
-                       $matches = array();
-                       if ( isset( $limits['subnet'] ) && preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
-                               $subnet = $matches[1];
-                               $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
+                       if ( isset( $limits['subnet'] ) ) {
+                               $ip = $this->getRequest()->getIP();
+                               $matches = array();
+                               $subnet = false;
+                               if ( IP::isIPv6( $ip ) ) {
+                                       $parts = IP::parseRange( "$ip/64" );
+                                       $subnet = $parts[0];
+                               } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
+                                       // IPv4
+                                       $subnet = $matches[1];
+                               }
+                               if ( $subnet !== false ) {
+                                       $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
+                               }
                        }
                }
                // Check for group-specific permissions