Page MenuHomePhorge

No OneTemporary

Size
5 KB
Referenced Files
None
Subscribers
None
diff --git a/maintenance/cleanupBlocks.php b/maintenance/cleanupBlocks.php
index c9f8af43af7..56a8f47851e 100644
--- a/maintenance/cleanupBlocks.php
+++ b/maintenance/cleanupBlocks.php
@@ -1,6 +1,7 @@
<?php
use MediaWiki\Maintenance\Maintenance;
+use Wikimedia\IPUtils;
require_once __DIR__ . '/Maintenance.php';
@@ -18,6 +19,7 @@ class CleanupBlocks extends Maintenance {
$this->deleteOrphanBlockTargets();
$this->deleteTargetlessBlocks();
+ $this->normalizeAddresses();
$this->mergeDuplicateBlockTargets();
$this->fixTargetCounts();
}
@@ -127,6 +129,88 @@ class CleanupBlocks extends Maintenance {
$this->output( $affected ? "OK\n" : "no rows affected\n" );
}
+ /**
+ * Fix IP address normalization issues:
+ * - Leading zeroes like 1.1.1.001
+ * - Lower-case IPv6 addresses like 200e::
+ * - Non-zero range suffixes like 1.1.1.111/24
+ */
+ private function normalizeAddresses() {
+ $dbr = $this->getReplicaDB();
+ $dbType = $dbr->getType();
+ if ( $dbType !== 'mysql' ) {
+ $this->output( "Skipping IP address normalization: not implemented on $dbType\n" );
+ return;
+ }
+ $res = $dbr->newSelectQueryBuilder()
+ ->select( [ 'bt_id', 'bt_address' ] )
+ ->from( 'block_target' )
+ ->where( [ 'bt_user' => null ] )
+ ->andWhere( 'bt_range_start IS NOT NULL OR ' .
+ 'bt_address RLIKE \'(^|[.:])0[0-9]|[a-f]|::\'' )
+ ->caller( __METHOD__ )
+ ->fetchResultSet();
+ $writeDone = false;
+ foreach ( $res as $row ) {
+ $addr = $row->bt_address;
+ if ( IPUtils::isValid( $addr ) ) {
+ $norm = IPUtils::sanitizeIP( $addr );
+ } elseif ( IPUtils::isValidRange( $addr ) ) {
+ $norm = IPUtils::sanitizeRange( $addr );
+ } else {
+ continue;
+ }
+ if ( $addr !== $norm && is_string( $norm ) ) {
+ $this->normalizeAddress( (int)$row->bt_id, $addr, $norm );
+ $writeDone = true;
+ }
+ }
+ if ( $writeDone ) {
+ // Ensure that mergeDuplicateBlockTargets() sees our changes
+ $this->waitForReplication();
+ }
+ }
+
+ /**
+ * Normalize the IP address in a single block_target row
+ *
+ * @param int $targetId
+ * @param string $address
+ * @param string $normalizedAddress
+ */
+ private function normalizeAddress( int $targetId, string $address, string $normalizedAddress ) {
+ $this->output( "Normalizing bt_id=$targetId $address -> $normalizedAddress: " );
+ if ( $this->dryRun ) {
+ $this->output( "dry run\n" );
+ return;
+ }
+ $dbw = $this->getPrimaryDB();
+ $dbw->startAtomic( __METHOD__ );
+ $primaryAddr = $dbw->newSelectQueryBuilder()
+ ->select( 'bt_address' )
+ ->from( 'block_target' )
+ ->where( [ 'bt_id' => $targetId ] )
+ ->forUpdate()
+ ->caller( __METHOD__ )
+ ->fetchField();
+ if ( $primaryAddr === false ) {
+ $this->output( "missing in primary\n" );
+ return;
+ }
+ if ( $primaryAddr !== $address ) {
+ $this->output( "changed in primary\n" );
+ return;
+ }
+ $dbw->newUpdateQueryBuilder()
+ ->update( 'block_target' )
+ ->set( [ 'bt_address' => $normalizedAddress ] )
+ ->where( [ 'bt_id' => $targetId ] )
+ ->caller( __METHOD__ )
+ ->execute();
+ $dbw->endAtomic( __METHOD__ );
+ $this->output( "done\n" );
+ }
+
/**
* Merge block_target rows referring to the same user, IP address or range
*/
diff --git a/tests/phpunit/maintenance/CleanupBlocksTest.php b/tests/phpunit/maintenance/CleanupBlocksTest.php
index 1d4f4f417a6..136d29f2fe5 100644
--- a/tests/phpunit/maintenance/CleanupBlocksTest.php
+++ b/tests/phpunit/maintenance/CleanupBlocksTest.php
@@ -2,7 +2,10 @@
namespace MediaWiki\Tests\Maintenance;
+use MediaWiki\Block\AnonIpBlockTarget;
use MediaWiki\Block\DatabaseBlock;
+use MediaWiki\Block\RangeBlockTarget;
+use MediaWiki\MainConfigNames;
use MediaWiki\User\UserIdentityValue;
/**
@@ -25,6 +28,9 @@ class CleanupBlocksTest extends MaintenanceBaseTestCase {
'by' => new UserIdentityValue( 100, 'Admin' ),
'address' => '127.0.0.1',
];
+ if ( isset( $options['target'] ) ) {
+ unset( $options['address'] );
+ }
return $this->getServiceContainer()->getDatabaseBlockStore()
->insertBlockWithParams( $options );
}
@@ -68,6 +74,42 @@ class CleanupBlocksTest extends MaintenanceBaseTestCase {
->assertFieldValues( [ (string)$block1->getId() ] );
}
+ public function testNormalizeAddresses() {
+ if ( $this->getDb()->getType() !== 'mysql' ) {
+ $this->markTestSkipped( 'not implemented on this DBMS' );
+ }
+ $this->insertBlock();
+ $this->insertBlock( [ 'target' => new AnonIpBlockTarget( '1.1.1.001' ) ] );
+ $this->insertBlock( [ 'target' => new AnonIpBlockTarget( '300e:0:0:0:0:0:0:0' ) ] );
+ $this->insertBlock( [
+ 'target' => new RangeBlockTarget(
+ '2.1.1.111/24',
+ $this->getConfVar( MainConfigNames::BlockCIDRLimit )
+ )
+ ] );
+
+ $this->newSelectQueryBuilder()
+ ->select( 'bt_address' )
+ ->from( 'block_target' )
+ ->assertFieldValues( [
+ '1.1.1.001',
+ '127.0.0.1',
+ '2.1.1.111/24',
+ '300e:0:0:0:0:0:0:0',
+ ] );
+
+ $this->maintenance->execute();
+ $this->newSelectQueryBuilder()
+ ->select( 'bt_address' )
+ ->from( 'block_target' )
+ ->assertFieldValues( [
+ '1.1.1.1',
+ '127.0.0.1',
+ '2.1.1.0/24',
+ '300E:0:0:0:0:0:0:0',
+ ] );
+ }
+
public function testMergeDuplicateBlockTargets() {
$block1 = $this->insertBlock();
$b1 = $block1->getId();

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jul 5, 5:31 AM (11 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
227435
Default Alt Text
(5 KB)

Event Timeline