summaryrefslogtreecommitdiff
path: root/FS/FS/Misc
diff options
context:
space:
mode:
authorMitch Jackson <mitch@freeside.biz>2018-07-10 23:30:48 -0500
committerMitch Jackson <mitch@freeside.biz>2018-10-19 19:53:57 -0400
commita7d14a749e808369e22aa1b0026af5bc74225961 (patch)
tree1b8cd7f049523bd6446a844018dbc1394e986775 /FS/FS/Misc
parent1b4b7af57df5a6b9bbf7c27a63119a431ca4f847 (diff)
RT# 80555 freeside_upgrade for invalid ip addresses
Diffstat (limited to 'FS/FS/Misc')
-rw-r--r--FS/FS/Misc/FixIPFormat.pm124
1 files changed, 124 insertions, 0 deletions
diff --git a/FS/FS/Misc/FixIPFormat.pm b/FS/FS/Misc/FixIPFormat.pm
new file mode 100644
index 0000000..3f9a19b
--- /dev/null
+++ b/FS/FS/Misc/FixIPFormat.pm
@@ -0,0 +1,124 @@
+package FS::Misc::FixIPFormat;
+use strict;
+use warnings;
+use FS::Record qw(dbh qsearchs);
+use FS::upgrade_journal;
+
+=head1 NAME
+
+FS::Misc::FixIPFormat - Functions to repair bad IP address input
+
+=head1 DESCRIPTION
+
+Provides functions for freeside_upgrade to check IP address storage for
+user-entered leading 0's in IP addresses. When read from database, NetAddr::IP
+would treat the number as octal isntead of decimal. If a user entered
+10.0.0.052, this may get invisibly translated to 10.0.0.42 when exported.
+Base8:52 = Base0:42
+
+Tied to freeside_upgrade with journal name TABLE__fixipformat
+
+see: RT# 80555
+
+=head1 SYNOPSIS
+
+Usage:
+
+ # require, not use - this module is only run once
+ require FS::Misc::FixIPFormat;
+
+ my $error = FS::Misc::FixIPFormat::fix_bad_addresses_in_table(
+ 'svc_broadband', 'svcnum', 'ip_addr'
+ );
+ die "oh no!" if $error;
+
+=head2 fix_bad_addresses_in_table TABLE, ID_COLUMN, IP_COLUMN
+
+$error = fix_bad_addresses_in_table( 'svc_broadband', 'svcnum', 'ip_addr' );
+
+=cut
+
+sub fix_bad_addresses_in_table {
+ my ( $table ) = @_;
+ return if FS::upgrade_journal->is_done("${table}__fixipformat");
+ for my $id ( find_bad_addresses_in_table( @_ )) {
+ if ( my $error = fix_ip_for_record( $id, @_ )) {
+ die "fix_bad_addresses_in_table(): $error";
+ }
+ }
+ FS::upgrade_journal->set_done("${table}__fixipformat");
+ 0;
+}
+
+=head2 find_bad_addresses_in_table TABLE, ID_COLUMN, IP_COLUMN
+
+@id = find_bad_addresses_in_table( 'svc_broadband', 'svcnum', 'ip_addr' );
+
+=cut
+
+sub find_bad_addresses_in_table {
+ my ( $table, $id_col, $ip_col ) = @_;
+ my @fix_ids;
+
+ # using DBI directly for performance
+ my $sql_statement = "
+ SELECT $id_col, $ip_col
+ FROM $table
+ WHERE $ip_col IS NOT NULL
+ ";
+ my $sth = dbh->prepare( $sql_statement ) || die "SQL ERROR ".dbh->errstr;
+ $sth->execute || die "SQL ERROR ".dbh->errstr;
+ while ( my $row = $sth->fetchrow_hashref ) {
+ push @fix_ids, $row->{ $id_col }
+ if $row->{ $ip_col } =~ /[\.^]0\d/;
+ }
+ @fix_ids;
+}
+
+=head2 fix_ip_for_record ID, TABLE, ID_COLUMN, IP_COLUMN
+
+Attempt to strip the leading 0 from a stored IP address record. If
+the corrected IP address would be a duplicate of another record in the
+same table, thow an exception.
+
+$error = fix_ip_for_record( 1001, 'svc_broadband', 'svcnum', 'ip_addr', );
+
+=cut
+
+sub fix_ip_for_record {
+ my ( $id, $table, $id_col, $ip_col ) = @_;
+
+ my $row = qsearchs($table, {$id_col => $id})
+ || die "Error finding $table record for id $id";
+
+ my $ip = $row->getfield( $ip_col );
+ my $fixed_ip = join( '.',
+ map{ int($_) }
+ split( /\./, $ip )
+ );
+
+ return undef unless $ip ne $fixed_ip;
+
+ if ( my $dupe_row = qsearchs( $table, {$ip_col => $fixed_ip} )) {
+ if ( $dupe_row->getfield( $id_col ) != $row->getfield( $id_col )) {
+ # Another record in the table has this IP address
+ # Eg one ip is provisioned as 10.0.0.51 and another is
+ # provisioned as 10.0.0.051. Cannot auto-correct by simply
+ # trimming leading 0. Die, let support decide how to fix.
+
+ die "Invalid IP address could not be auto-corrected - ".
+ "($table - $id_col = $id, $ip_col = $ip) ".
+ "colission with another reocrd - ".
+ "($table - $id_col = ".$dupe_row->getfield( $id_col )." ".
+ "$ip_col = ",$dupe_row->getfield( $ip_col )." ) - ".
+ "The entry must be corrected to continue";
+ }
+ }
+
+ warn "Autocorrecting IP address problem for ".
+ "($table - $id_col = $id, $ip_col = $ip) $fixed_ip\n";
+ $row->setfield( $ip_col, $fixed_ip );
+ $row->replace;
+}
+
+1;