[6] | 1 | #!/usr/bin/perl
|
---|
[8] | 2 | # ipdb/cgi-bin/consistency-check.pl
|
---|
[6] | 3 | # Does full check to see if the data in the db is consistent and complete.
|
---|
[901] | 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.
|
---|
[8] | 7 | ###
|
---|
| 8 | # SVN revision info
|
---|
| 9 | # $Date: 2017-02-10 17:01:25 +0000 (Fri, 10 Feb 2017) $
|
---|
| 10 | # SVN revision $Rev: 901 $
|
---|
| 11 | # Last update by $Author: kdeugau $
|
---|
| 12 | ###
|
---|
[901] | 13 | # Copyright (C) 2004-2010,2014,2017 - Kris Deugau
|
---|
[6] | 14 |
|
---|
[901] | 15 | use strict;
|
---|
| 16 | use warnings;
|
---|
| 17 |
|
---|
[6] | 18 | use DBI;
|
---|
| 19 | use NetAddr::IP;
|
---|
[635] | 20 | use Data::Dumper;
|
---|
[6] | 21 |
|
---|
[417] | 22 | # don't remove! required for GNU/FHS-ish install from tarball
|
---|
| 23 | ##uselib##
|
---|
| 24 |
|
---|
| 25 | use MyIPDB;
|
---|
| 26 |
|
---|
[901] | 27 | # Convenience for calling from admin tools
|
---|
[214] | 28 | print "Content-type: text/plain\n\n";
|
---|
| 29 |
|
---|
[901] | 30 | my ($dbh,$errstr) = connectDB_My;
|
---|
[402] | 31 | die $errstr if !$dbh;
|
---|
[167] | 32 | # May as well. We need a number of globals.
|
---|
| 33 | initIPDBGlobals($dbh);
|
---|
[6] | 34 |
|
---|
[901] | 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);
|
---|
[635] | 40 | }
|
---|
| 41 |
|
---|
[901] | 42 | print "\nChecking that all allocations are referenced:\n";
|
---|
| 43 | $sth = $dbh->prepare("SELECT id FROM allocations");
|
---|
[6] | 44 | $sth->execute;
|
---|
[901] | 45 | my $i = 0;
|
---|
| 46 | while (my ($id) = $sth->fetchrow_array) {
|
---|
| 47 | delete $idlist{$id};
|
---|
| 48 | $i++;
|
---|
[6] | 49 | }
|
---|
[901] | 50 | print " $i allocations confirmed referenced\n";
|
---|
| 51 | $i = 0;
|
---|
| 52 | $sth = $dbh->prepare("SELECT id FROM freeblocks");
|
---|
[6] | 53 | $sth->execute;
|
---|
[901] | 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";
|
---|
[6] | 64 | }
|
---|
| 65 | }
|
---|
| 66 |
|
---|
[901] | 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");
|
---|
[6] | 69 | $sth->execute;
|
---|
[901] | 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};
|
---|
[6] | 73 | }
|
---|
[901] | 74 | print "Done predefined CustID correctness check.\n\n";
|
---|
[6] | 75 |
|
---|
[901] | 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");
|
---|
[62] | 79 | $sth->execute;
|
---|
[901] | 80 | while (my ($cidr,$custid,$desc) = $sth->fetchrow_array) {
|
---|
| 81 | print "cn block $cidr ($desc) has incorrect CustID $custid\n";
|
---|
[62] | 82 | }
|
---|
[901] | 83 | print "Done checking customer blocks\n";
|
---|
[62] | 84 |
|
---|
[901] | 85 | exit;
|
---|
[62] | 86 |
|
---|
[190] | 87 |
|
---|
[901] | 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;
|
---|
[6] | 93 |
|
---|
[901] | 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);
|
---|
[6] | 101 |
|
---|
[901] | 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";
|
---|
[11] | 106 |
|
---|
[901] | 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]/;
|
---|
[635] | 120 | my $prevn = $prev->broadcast->numeric + 1;
|
---|
[901] | 121 | my $cur = new NetAddr::IP $childnet;
|
---|
[635] | 122 | if ($cur->numeric == $prevn) {
|
---|
| 123 | $prev = $cur;
|
---|
| 124 | next;
|
---|
| 125 | }
|
---|
[901] | 126 | if ($ccidr->numeric == $prev->numeric) {
|
---|
[11] | 127 | # check if cur starts with master
|
---|
| 128 | if ($cur->numeric > $prev->numeric) {
|
---|
[901] | 129 | print $indent." Gap from start of parent $ccidr to first block $cur\n";
|
---|
[11] | 130 | } elsif ($cur->numeric < $prev->numeric) {
|
---|
[901] | 131 | print $indent." BIG problem! Current block $cur begins before parent $ccidr!\n";
|
---|
[11] | 132 | }
|
---|
[6] | 133 | } else {
|
---|
[11] | 134 | if ($cur->numeric < ($prev->numeric + 1)) {
|
---|
[901] | 135 | print $indent." Block ".$prev->network." overlaps block $cur\n";
|
---|
[11] | 136 | } elsif ($cur->numeric > ($prev->numeric + 1)) {
|
---|
[901] | 137 | print $indent." Gap between end of block ".$prev->network." and block $cur\n";
|
---|
[11] | 138 | }
|
---|
[6] | 139 | }
|
---|
[11] | 140 |
|
---|
| 141 | $prev = $cur;
|
---|
| 142 | $prev--;
|
---|
[6] | 143 | }
|
---|
| 144 | }
|
---|