[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-08-15 17:53:23 +0000 (Tue, 15 Aug 2017) $
|
---|
| 10 | # SVN revision $Rev: 906 $
|
---|
| 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 |
|
---|
[906] | 25 | # push "the directory the script is in" into @INC
|
---|
| 26 | use FindBin;
|
---|
| 27 | use lib "$FindBin::RealBin/";
|
---|
| 28 |
|
---|
[417] | 29 | use MyIPDB;
|
---|
| 30 |
|
---|
[901] | 31 | # Convenience for calling from admin tools
|
---|
[214] | 32 | print "Content-type: text/plain\n\n";
|
---|
| 33 |
|
---|
[901] | 34 | my ($dbh,$errstr) = connectDB_My;
|
---|
[402] | 35 | die $errstr if !$dbh;
|
---|
[167] | 36 | # May as well. We need a number of globals.
|
---|
| 37 | initIPDBGlobals($dbh);
|
---|
[6] | 38 |
|
---|
[901] | 39 | my %idlist;
|
---|
| 40 | my $sth = $dbh->prepare("SELECT id FROM allocations WHERE type='mm' ORDER BY cidr");
|
---|
| 41 | $sth->execute;
|
---|
| 42 | while (my ($mid) = $sth->fetchrow_array) {
|
---|
| 43 | checkcontainer($mid, \%idlist, 0);
|
---|
[635] | 44 | }
|
---|
| 45 |
|
---|
[901] | 46 | print "\nChecking that all allocations are referenced:\n";
|
---|
| 47 | $sth = $dbh->prepare("SELECT id FROM allocations");
|
---|
[6] | 48 | $sth->execute;
|
---|
[901] | 49 | my $i = 0;
|
---|
| 50 | while (my ($id) = $sth->fetchrow_array) {
|
---|
| 51 | delete $idlist{$id};
|
---|
| 52 | $i++;
|
---|
[6] | 53 | }
|
---|
[901] | 54 | print " $i allocations confirmed referenced\n";
|
---|
| 55 | $i = 0;
|
---|
| 56 | $sth = $dbh->prepare("SELECT id FROM freeblocks");
|
---|
[6] | 57 | $sth->execute;
|
---|
[901] | 58 | while (my ($id) = $sth->fetchrow_array) {
|
---|
| 59 | delete $idlist{'fb'.$id};
|
---|
| 60 | $i++;
|
---|
| 61 | }
|
---|
| 62 | print " $i freeblocks confirmed referenced\n";
|
---|
| 63 | foreach (keys %idlist) {
|
---|
| 64 | if (/^fb/) {
|
---|
| 65 | print " Unreferenced free block ID $_, $idlist{$_}\n";
|
---|
| 66 | } else {
|
---|
| 67 | print " Unreferenced block ID $_, $idlist{$_}\n";
|
---|
[6] | 68 | }
|
---|
| 69 | }
|
---|
| 70 |
|
---|
[901] | 71 | print "\nChecking for correctness on 'defined' CustIDs:\n";
|
---|
| 72 | $sth = $dbh->prepare("SELECT cidr,type,custid FROM allocations WHERE NOT (type='cn' OR type LIKE '_r') ORDER BY cidr");
|
---|
[6] | 73 | $sth->execute;
|
---|
[901] | 74 | while (my($cidr,$type,$custid) = $sth->fetchrow_array) {
|
---|
| 75 | print "$cidr ($disp_alloctypes{$type}) has incorrect CustID $custid\n"
|
---|
| 76 | if $custid ne $def_custids{$type};
|
---|
[6] | 77 | }
|
---|
[901] | 78 | print "Done predefined CustID correctness check.\n\n";
|
---|
[6] | 79 |
|
---|
[901] | 80 | print "Checking for customer blocks with 'bad' CustIDs:\n";
|
---|
| 81 | # Make sure cn-type ("customer netblock") blocks have "real" CustIDs.
|
---|
| 82 | $sth = $dbh->prepare("SELECT cidr,custid,description FROM allocations WHERE type='cn' AND (custid='$IPDB::defcustid' OR custid='STAFF') ORDER BY cidr");
|
---|
[62] | 83 | $sth->execute;
|
---|
[901] | 84 | while (my ($cidr,$custid,$desc) = $sth->fetchrow_array) {
|
---|
| 85 | print "cn block $cidr ($desc) has incorrect CustID $custid\n";
|
---|
[62] | 86 | }
|
---|
[901] | 87 | print "Done checking customer blocks\n";
|
---|
[62] | 88 |
|
---|
[901] | 89 | exit;
|
---|
[62] | 90 |
|
---|
[190] | 91 |
|
---|
[901] | 92 | # All we need to check on is "do the allocations and free blocks within a container completely make up the container?"
|
---|
| 93 | sub checkcontainer {
|
---|
| 94 | my $cid = shift;
|
---|
| 95 | my $idlist = shift;
|
---|
| 96 | my $depth = shift;
|
---|
[6] | 97 |
|
---|
[901] | 98 | # snarf the container's CIDR
|
---|
| 99 | my $sth = $dbh->prepare("SELECT cidr,type FROM allocations WHERE id = ?");
|
---|
| 100 | $sth->execute($cid);
|
---|
| 101 | my ($ccidr,$ctype) = $sth->fetchrow_array();
|
---|
| 102 | # note that we've "seen" the ID/CIDR
|
---|
| 103 | $idlist->{$cid} = $ccidr;
|
---|
| 104 | $ccidr = NetAddr::IP->new($ccidr);
|
---|
[6] | 105 |
|
---|
[901] | 106 | $depth++;
|
---|
| 107 | print "error: gone too deep ($depth). breaking off\n" if $depth > 6;
|
---|
| 108 | my $indent = ' ' x $depth;
|
---|
| 109 | print $indent."Checking $disp_alloctypes{$ctype} $ccidr ($cid)\n";
|
---|
[11] | 110 |
|
---|
[901] | 111 | $sth = $dbh->prepare(qq(
|
---|
| 112 | SELECT id, cidr, type, network(cidr) AS net, broadcast(cidr) AS bcast FROM allocations WHERE parent_id = ?
|
---|
| 113 | UNION
|
---|
| 114 | SELECT id, cidr, 'f' AS type, network(cidr) AS net, broadcast(cidr) AS bcast FROM freeblocks WHERE parent_id = ?
|
---|
| 115 | ORDER BY cidr
|
---|
| 116 | ));
|
---|
| 117 | $sth->execute($cid, $cid) or die $dbh->errstr;
|
---|
| 118 | my $prev = $ccidr;
|
---|
| 119 | while (my ($childid, $childcidr, $childtype, $childnet, $childbcast) = $sth->fetchrow_array) {
|
---|
| 120 | # note that we've "seen" the ID/CIDR, flagging freeblocks
|
---|
| 121 | $idlist->{$childid} = $childcidr if $childtype ne 'f';
|
---|
| 122 | $idlist->{'fb'.$childid} = $childcidr if $childtype eq 'f';
|
---|
| 123 | checkcontainer($childid, $idlist, $depth) if $childtype =~ /.[cm]/;
|
---|
[635] | 124 | my $prevn = $prev->broadcast->numeric + 1;
|
---|
[901] | 125 | my $cur = new NetAddr::IP $childnet;
|
---|
[635] | 126 | if ($cur->numeric == $prevn) {
|
---|
| 127 | $prev = $cur;
|
---|
| 128 | next;
|
---|
| 129 | }
|
---|
[901] | 130 | if ($ccidr->numeric == $prev->numeric) {
|
---|
[11] | 131 | # check if cur starts with master
|
---|
| 132 | if ($cur->numeric > $prev->numeric) {
|
---|
[901] | 133 | print $indent." Gap from start of parent $ccidr to first block $cur\n";
|
---|
[11] | 134 | } elsif ($cur->numeric < $prev->numeric) {
|
---|
[901] | 135 | print $indent." BIG problem! Current block $cur begins before parent $ccidr!\n";
|
---|
[11] | 136 | }
|
---|
[6] | 137 | } else {
|
---|
[11] | 138 | if ($cur->numeric < ($prev->numeric + 1)) {
|
---|
[901] | 139 | print $indent." Block ".$prev->network." overlaps block $cur\n";
|
---|
[11] | 140 | } elsif ($cur->numeric > ($prev->numeric + 1)) {
|
---|
[901] | 141 | print $indent." Gap between end of block ".$prev->network." and block $cur\n";
|
---|
[11] | 142 | }
|
---|
[6] | 143 | }
|
---|
[11] | 144 |
|
---|
| 145 | $prev = $cur;
|
---|
| 146 | $prev--;
|
---|
[6] | 147 | }
|
---|
| 148 | }
|
---|