Ignore:
Timestamp:
02/10/17 12:01:25 (8 years ago)
Author:
Kris Deugau
Message:

/trunk

Major update to consistency-check.pl due to ongoing changes in back end

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/cgi-bin/consistency-check.pl

    r635 r901  
    22# ipdb/cgi-bin/consistency-check.pl
    33# 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.
    47###
    58# SVN revision info
     
    811# Last update by $Author$
    912###
    10 # Copyright (C) 2004-2010 - Kris Deugau
     13# Copyright (C) 2004-2010,2014,2017 - Kris Deugau
     14
     15use strict;
     16use warnings;
    1117
    1218use DBI;
     
    1925use MyIPDB;
    2026
     27# Convenience for calling from admin tools
    2128print "Content-type: text/plain\n\n";
    2229
    23 ($dbh,$errstr) = connectDB_My;
     30my ($dbh,$errstr) = connectDB_My;
    2431die $errstr if !$dbh;
    2532# May as well.  We need a number of globals.
    2633initIPDBGlobals($dbh);
    2734
    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});
     35my %idlist;
     36my $sth = $dbh->prepare("SELECT id FROM allocations WHERE type='mm' ORDER BY cidr");
     37$sth->execute;
     38while (my ($mid) = $sth->fetchrow_array) {
     39  checkcontainer($mid, \%idlist, 0);
    3540}
    3641
    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");
     42print "\nChecking that all allocations are referenced:\n";
     43$sth = $dbh->prepare("SELECT id FROM allocations");
    4344$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; }
     45my $i = 0;
     46while (my ($id) = $sth->fetchrow_array) {
     47  delete $idlist{$id};
     48  $i++;
     49}
     50print "  $i allocations confirmed referenced\n";
     51$i = 0;
     52$sth = $dbh->prepare("SELECT id FROM freeblocks");
     53$sth->execute;
     54while (my ($id) = $sth->fetchrow_array) {
     55  delete $idlist{'fb'.$id};
     56  $i++;
     57}
     58print "  $i freeblocks confirmed referenced\n";
     59foreach (keys %idlist) {
     60  if (/^fb/) {
     61    print "  Unreferenced free block ID $_, $idlist{$_}\n";
     62  } else {
     63    print "  Unreferenced block ID $_, $idlist{$_}\n";
    5064  }
    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 blocks
    72 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 '');
    10565}
    10666
    107 print "Done checking pool containment.\n\n";
     67print "\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;
     70while (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}
     74print "Done predefined CustID correctness check.\n\n";
    10875
    109 print "Checking block-alignment consistency...\n";
     76print "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;
     80while (my ($cidr,$custid,$desc) = $sth->fetchrow_array) {
     81  print "cn block $cidr ($desc) has incorrect CustID $custid\n";
     82}
     83print "Done checking customer blocks\n";
    11084
    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.
     85exit;
    11986
    120 # (select cidr from allocations where cidr <<= '$master') union
    121 #  (select cidr from freeblocks where cidr <<= '$master')
    122 #  order by cidr
    12387
    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?"
     89sub checkcontainer {
     90  my $cid = shift;
     91  my $idlist = shift;
     92  my $depth = shift;
    13293
    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]/;
    134120    my $prevn = $prev->broadcast->numeric + 1;
    135     $cur = new NetAddr::IP $net;
     121    my $cur = new NetAddr::IP $childnet;
    136122    if ($cur->numeric == $prevn) {
    137123      $prev = $cur;
    138124      next;
    139125    }
    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) {
    143127      # check if cur starts with master
    144128      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";
    146130      } 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";
    148132      }
    149133    } else {
    150134      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";
    152136      } 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";
    154138      }
    155139    }
     
    157141    $prev = $cur;
    158142    $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";
    166143  }
    167   $master++;
    168   print "  done $master.\n";
    169144}
    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 within
    176 # 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 master
    223       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.