Changeset 901 for trunk/cgi-bin/consistency-check.pl
- Timestamp:
- 02/10/17 12:01:25 (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cgi-bin/consistency-check.pl
r635 r901 2 2 # ipdb/cgi-bin/consistency-check.pl 3 3 # Does full check to see if the data in the db is consistent and complete. 4 # Note this can't account for slightly squirrelly or pretzelly legacy data; 5 # that has to be hand-verified when this script chokes on it and spits up 6 # errors. 4 7 ### 5 8 # SVN revision info … … 8 11 # Last update by $Author$ 9 12 ### 10 # Copyright (C) 2004-2010 - Kris Deugau 13 # Copyright (C) 2004-2010,2014,2017 - Kris Deugau 14 15 use strict; 16 use warnings; 11 17 12 18 use DBI; … … 19 25 use MyIPDB; 20 26 27 # Convenience for calling from admin tools 21 28 print "Content-type: text/plain\n\n"; 22 29 23 ($dbh,$errstr) = connectDB_My;30 my ($dbh,$errstr) = connectDB_My; 24 31 die $errstr if !$dbh; 25 32 # May as well. We need a number of globals. 26 33 initIPDBGlobals($dbh); 27 34 28 ## Do some new init things to account for IPDB.pm changes 29 my $tmp; 30 # get master blocks in an array 31 my @masterblocks; 32 $tmp = getMasterList($dbh); 33 foreach (@{$tmp}) { 34 push @masterblocks, NetAddr::IP->new($_->{master}); 35 my %idlist; 36 my $sth = $dbh->prepare("SELECT id FROM allocations WHERE type='mm' ORDER BY cidr"); 37 $sth->execute; 38 while (my ($mid) = $sth->fetchrow_array) { 39 checkcontainer($mid, \%idlist, 0); 35 40 } 36 41 37 print "Checking master containment...\n"; 38 39 # First check - make sure ALL routes and allocated blocks are part 40 # of one of the master blocks. 41 print " Checking routed blocks:"; 42 $sth = $dbh->prepare("select cidr from routed"); 42 print "\nChecking that all allocations are referenced:\n"; 43 $sth = $dbh->prepare("SELECT id FROM allocations"); 43 44 $sth->execute; 44 $flag = ''; 45 my $i; 46 ROUTED: while (@data = $sth->fetchrow_array) { 47 $cidr = new NetAddr::IP $data[0]; 48 foreach $master (@masterblocks) { 49 if ($master->contains($cidr)) { next ROUTED; } 45 my $i = 0; 46 while (my ($id) = $sth->fetchrow_array) { 47 delete $idlist{$id}; 48 $i++; 49 } 50 print " $i allocations confirmed referenced\n"; 51 $i = 0; 52 $sth = $dbh->prepare("SELECT id FROM freeblocks"); 53 $sth->execute; 54 while (my ($id) = $sth->fetchrow_array) { 55 delete $idlist{'fb'.$id}; 56 $i++; 57 } 58 print " $i freeblocks confirmed referenced\n"; 59 foreach (keys %idlist) { 60 if (/^fb/) { 61 print " Unreferenced free block ID $_, $idlist{$_}\n"; 62 } else { 63 print " Unreferenced block ID $_, $idlist{$_}\n"; 50 64 } 51 print "\n $cidr not mastered";52 last if $i++>10;53 }54 print "$flag done.\n";55 56 # Next test: All allocations must be part of a master.57 print " Checking allocations:";58 $sth = $dbh->prepare("select cidr from allocations");59 $sth->execute;60 $flag = '';61 ALLOCATED: while (@data = $sth->fetchrow_array) {62 $cidr = new NetAddr::IP $data[0];63 foreach $master (@masterblocks) {64 if ($master->contains($cidr)) { next ALLOCATED; }65 }66 print "\n $cidr not mastered";67 $flag = "\n ";68 }69 print "$flag done.\n";70 71 # Next: free blocks72 print " Checking freeblocks:";73 $sth = $dbh->prepare("select cidr from freeblocks order by cidr");74 $sth->execute;75 $flag = '';76 FREEBLOCK: while (@data = $sth->fetchrow_array) {77 $cidr = new NetAddr::IP $data[0];78 foreach $master (@masterblocks) {79 if ($master->contains($cidr)) { next FREEBLOCK; }80 }81 print "\n $cidr not mastered";82 $flag = "\n ";83 }84 print "$flag done.\n";85 86 print "Done checking master containment.\n\n";87 88 print "Checking pool containment...\n";89 90 $sth = $dbh->prepare("select pool,ip from poolips order by ip");91 $sth->execute;92 while (@data = $sth->fetchrow_array) {93 $pool = new NetAddr::IP $data[0];94 $ip = new NetAddr::IP $data[1];95 print " IP $ip listed with incorrect pool $pool\n"96 if !$pool->contains($ip);97 }98 $sth = $dbh->prepare("select distinct pool from poolips order by pool");99 $sth->execute;100 while (@data = $sth->fetchrow_array) {101 $sth2 = $dbh->prepare("select cidr from allocations where cidr='$data[0]'");102 $sth2->execute;103 print " Pool $data[0] does not exist in allocations table\n"104 if (($sth2->fetchrow_array)[0] eq '');105 65 } 106 66 107 print "Done checking pool containment.\n\n"; 67 print "\nChecking for correctness on 'defined' CustIDs:\n"; 68 $sth = $dbh->prepare("SELECT cidr,type,custid FROM allocations WHERE NOT (type='cn' OR type LIKE '_r') ORDER BY cidr"); 69 $sth->execute; 70 while (my($cidr,$type,$custid) = $sth->fetchrow_array) { 71 print "$cidr ($disp_alloctypes{$type}) has incorrect CustID $custid\n" 72 if $custid ne $def_custids{$type}; 73 } 74 print "Done predefined CustID correctness check.\n\n"; 108 75 109 print "Checking block-alignment consistency...\n"; 76 print "Checking for customer blocks with 'bad' CustIDs:\n"; 77 # Make sure cn-type ("customer netblock") blocks have "real" CustIDs. 78 $sth = $dbh->prepare("SELECT cidr,custid,description FROM allocations WHERE type='cn' AND (custid='$IPDB::defcustid' OR custid='STAFF') ORDER BY cidr"); 79 $sth->execute; 80 while (my ($cidr,$custid,$desc) = $sth->fetchrow_array) { 81 print "cn block $cidr ($desc) has incorrect CustID $custid\n"; 82 } 83 print "Done checking customer blocks\n"; 110 84 111 # Block alignment consistency: All allocated+free blocks within a master 112 # must NOT overlap, and they must show no gaps. 113 # eg, if we have blocks: 114 # master is 192.168.2.0/24 115 # allocated 192.168.2.0/29, 192.168.2.8/29, 192.168.2.64/26 116 # free 192.168.2.16/28, 192.168.2.32/27, 192.168.2.128/25 117 # then we're OK, but if any one of the allocated or free blocks is missing, 118 # something b0rked. 85 exit; 119 86 120 # (select cidr from allocations where cidr <<= '$master') union121 # (select cidr from freeblocks where cidr <<= '$master')122 # order by cidr123 87 124 foreach $master (@masterblocks) { 125 print " Master $master:\n"; 126 $prev = $master; 127 $sth = $dbh->prepare("(select network(cidr) as net, broadcast(cidr) as bcast ". 128 "from allocations where cidr <<= '$master' and not (type like '_c' or type in ('rm','mm')) ) ". 129 "union (select network(cidr) as net, broadcast(cidr) as bcast ". 130 "from freeblocks where cidr <<= '$master' and not (routed='c')) order by net"); 131 $sth->execute; 88 # All we need to check on is "do the allocations and free blocks within a container completely make up the container?" 89 sub checkcontainer { 90 my $cid = shift; 91 my $idlist = shift; 92 my $depth = shift; 132 93 133 while (my ($net,$bcast) = $sth->fetchrow_array) { 94 # snarf the container's CIDR 95 my $sth = $dbh->prepare("SELECT cidr,type FROM allocations WHERE id = ?"); 96 $sth->execute($cid); 97 my ($ccidr,$ctype) = $sth->fetchrow_array(); 98 # note that we've "seen" the ID/CIDR 99 $idlist->{$cid} = $ccidr; 100 $ccidr = NetAddr::IP->new($ccidr); 101 102 $depth++; 103 print "error: gone too deep ($depth). breaking off\n" if $depth > 6; 104 my $indent = ' ' x $depth; 105 print $indent."Checking $disp_alloctypes{$ctype} $ccidr ($cid)\n"; 106 107 $sth = $dbh->prepare(qq( 108 SELECT id, cidr, type, network(cidr) AS net, broadcast(cidr) AS bcast FROM allocations WHERE parent_id = ? 109 UNION 110 SELECT id, cidr, 'f' AS type, network(cidr) AS net, broadcast(cidr) AS bcast FROM freeblocks WHERE parent_id = ? 111 ORDER BY cidr 112 )); 113 $sth->execute($cid, $cid) or die $dbh->errstr; 114 my $prev = $ccidr; 115 while (my ($childid, $childcidr, $childtype, $childnet, $childbcast) = $sth->fetchrow_array) { 116 # note that we've "seen" the ID/CIDR, flagging freeblocks 117 $idlist->{$childid} = $childcidr if $childtype ne 'f'; 118 $idlist->{'fb'.$childid} = $childcidr if $childtype eq 'f'; 119 checkcontainer($childid, $idlist, $depth) if $childtype =~ /.[cm]/; 134 120 my $prevn = $prev->broadcast->numeric + 1; 135 $cur = new NetAddr::IP $net;121 my $cur = new NetAddr::IP $childnet; 136 122 if ($cur->numeric == $prevn) { 137 123 $prev = $cur; 138 124 next; 139 125 } 140 #print " 141 ##fixme: the rest of this could probably be squashed down quite a bit 142 if ($master->numeric == $prev->numeric) { 126 if ($ccidr->numeric == $prev->numeric) { 143 127 # check if cur starts with master 144 128 if ($cur->numeric > $prev->numeric) { 145 print " Gap from start of master $master to first block $cur\n";129 print $indent." Gap from start of parent $ccidr to first block $cur\n"; 146 130 } elsif ($cur->numeric < $prev->numeric) { 147 print " BIG problem! Current block $cur begins before master $master!\n";131 print $indent." BIG problem! Current block $cur begins before parent $ccidr!\n"; 148 132 } 149 133 } else { 150 134 if ($cur->numeric < ($prev->numeric + 1)) { 151 print "Block ".$prev->network." overlaps block $cur\n";135 print $indent." Block ".$prev->network." overlaps block $cur\n"; 152 136 } elsif ($cur->numeric > ($prev->numeric + 1)) { 153 print "Gap between end of block ".$prev->network." and block $cur\n";137 print $indent." Gap between end of block ".$prev->network." and block $cur\n"; 154 138 } 155 139 } … … 157 141 $prev = $cur; 158 142 $prev--; 159 160 } # while (@data...)161 162 $cur--;163 $master--;164 if ($cur->numeric ne $master->numeric) {165 print " Gap from $cur to end of master at $master\n";166 143 } 167 $master++;168 print " done $master.\n";169 144 } 170 171 print "Done checking block alignment.\n\n";172 173 print "Checking containment on container blocks...\n";174 # First, we need a list of containers.175 # Then, we check all of the contained blocks to see if they're within176 # the proper container.177 $sth = $dbh->prepare("select cidr from allocations where type like '_c' order by cidr");178 $sth->execute;179 $i=0;180 while (@data = $sth->fetchrow_array) {181 $containers[$i++] = new NetAddr::IP $data[0];182 }183 print " Checking general containment:";184 $sth = $dbh->prepare("select cidr from allocations where type like '_r' order by cidr");185 $sth->execute;186 $flag = '';187 CONTAINED: while (@data = $sth->fetchrow_array) {188 $cidr = new NetAddr::IP $data[0];189 foreach $container (@containers) {190 next CONTAINED if $container->contains($cidr);191 }192 print "\n $cidr not contained";193 $flag = "\n ";194 }195 print "$flag done.\n";196 print " Checking alignment:\n";197 foreach $container (@containers) {198 print " Container $container:\n";199 $prev = $container;200 $sth = $dbh->prepare("(select network(cidr) as net, broadcast(cidr) as bcast ".201 "from allocations where cidr <<= '$container' and type like '_r') ".202 "union (select network(cidr) as net, broadcast(cidr) as bcast ".203 "from freeblocks where cidr <<= '$container' and not (routed='y' or routed='n')) ".204 "order by net");205 $sth->execute;206 207 print "(select network(cidr) as net, broadcast(cidr) as bcast ".208 "from allocations where cidr <<= '$container' and type like '_r')\n ".209 "union (select network(cidr) as net, broadcast(cidr) as bcast ".210 "from freeblocks where cidr <<= '$container' and not (routed='y' or routed='n')) ".211 "order by net" if $container =~ /10.10.20/;212 213 while (my ($net,$bcast) = $sth->fetchrow_array) {214 my $prevn = $prev->broadcast->numeric + 1;215 $cur = new NetAddr::IP $net;216 if ($cur->numeric == $prevn) {217 $prev = $cur;218 next;219 }220 221 if ($container->numeric == $prev->numeric) {222 # check if cur starts with master223 if ($cur->numeric > $prev->numeric) {224 print " Gap from start of container $container to first block $cur\n";225 } elsif ($cur->numeric < $prev->numeric) {226 print " BIG problem! Current block $cur begins before container $container!\n";227 }228 } else {229 if ($cur->numeric < ($prev->numeric + 1)) {230 print " Block ".$prev->network." overlaps block $cur\n";231 } elsif ($cur->numeric > ($prev->numeric + 1)) {232 print " Gap between end of block ".$prev->network." and block $cur\n";233 }234 }235 236 $prev = $cur;237 $prev--;238 239 } # while (@data...)240 241 $cur--;242 $container--;243 if ($cur->numeric ne $container->numeric) {244 print " Gap from $cur to end of container at $container\n";245 }246 $container++;247 print " done $container.\n";248 249 }250 print " done container alignment.\n";251 print "Done checking container containment.\n\n";252 253 print "Checking for correctness on 'defined' CustIDs:\n";254 # New check: Make sure "defined" CustIDs are correct.255 $sth = $dbh->prepare("select cidr,type,custid from allocations where not (type='cn' or type like '_r') order by cidr");256 $sth->execute;257 while (@data = $sth->fetchrow_array) {258 print "$data[0] ($disp_alloctypes{$data[1]}) has incorrect CustID $data[2]\n"259 if $data[2] ne $def_custids{$data[1]};260 }261 print "Done predefined CustID correctness check.\n\n";262 263 print "Checking for customer blocks with 'bad' CustIDs:\n";264 # Make sure cn-type ("customer netblock") blocks have "real" CustIDs.265 $sth = $dbh->prepare("select cidr,type,custid from allocations where type='cn' and (custid='$IPDB::defcustid' or custid='STAFF') order by cidr");266 $sth->execute;267 while (@data = $sth->fetchrow_array) {268 print "cn block $data[0] has incorrect CustID $data[2]\n";269 }270 print "Done checking customer blocks\n";
Note:
See TracChangeset
for help on using the changeset viewer.