| 1 | #!/usr/bin/perl | 
|---|
| 2 | # consistency-check.pl | 
|---|
| 3 | # Does full check to see if the data in the db is consistent and complete. | 
|---|
| 4 |  | 
|---|
| 5 | use DBI; | 
|---|
| 6 | use IPDB qw(:ALL); | 
|---|
| 7 | use NetAddr::IP; | 
|---|
| 8 |  | 
|---|
| 9 | $dbh = connectDB; | 
|---|
| 10 |  | 
|---|
| 11 | # Schlep up the masters | 
|---|
| 12 | $sth = $dbh->prepare("select * from masterblocks order by cidr"); | 
|---|
| 13 | $sth->execute; | 
|---|
| 14 | for ($i=0; @data = $sth->fetchrow_array; $i++) { | 
|---|
| 15 | $masterblocks[$i] = new NetAddr::IP $data[0]; | 
|---|
| 16 | } | 
|---|
| 17 |  | 
|---|
| 18 | print "First check:  All blocks must be within one of the master blocks\n"; | 
|---|
| 19 |  | 
|---|
| 20 | # First check - make sure ALL routes and allocated blocks are part | 
|---|
| 21 | # of one of the master blocks. | 
|---|
| 22 | print "Checking routed blocks: "; | 
|---|
| 23 | $sth = $dbh->prepare("select cidr from routed"); | 
|---|
| 24 | # union select cidr from allocations union select cidr from freeblocks"); | 
|---|
| 25 | $sth->execute; | 
|---|
| 26 | ROUTED: while (@data = $sth->fetchrow_array) { | 
|---|
| 27 | $cidr = new NetAddr::IP $data[0]; | 
|---|
| 28 | foreach $master (@masterblocks) { | 
|---|
| 29 | if ($master->contains($cidr)) { next ROUTED; } | 
|---|
| 30 | } | 
|---|
| 31 | print "$cidr not mastered\n"; | 
|---|
| 32 | } | 
|---|
| 33 | print " done.\n"; | 
|---|
| 34 |  | 
|---|
| 35 | # Next test:  All allocations must be part of a master. | 
|---|
| 36 | print "Checking allocations: "; | 
|---|
| 37 | $sth = $dbh->prepare("select cidr from allocations"); | 
|---|
| 38 | $sth->execute; | 
|---|
| 39 | ALLOCATED: while (@data = $sth->fetchrow_array) { | 
|---|
| 40 | $cidr = new NetAddr::IP $data[0]; | 
|---|
| 41 | foreach $master (@masterblocks) { | 
|---|
| 42 | if ($master->contains($cidr)) { next ALLOCATED; } | 
|---|
| 43 | } | 
|---|
| 44 | print "$cidr not mastered\n"; | 
|---|
| 45 | } | 
|---|
| 46 | print " done.\n"; | 
|---|
| 47 |  | 
|---|
| 48 | # Next:  free blocks | 
|---|
| 49 | print "Checking freeblocks: "; | 
|---|
| 50 | $sth = $dbh->prepare("select cidr from freeblocks"); | 
|---|
| 51 | $sth->execute; | 
|---|
| 52 | FREEBLOCK: while (@data = $sth->fetchrow_array) { | 
|---|
| 53 | $cidr = new NetAddr::IP $data[0]; | 
|---|
| 54 | foreach $master (@masterblocks) { | 
|---|
| 55 | if ($master->contains($cidr)) { next FREEBLOCK; } | 
|---|
| 56 | } | 
|---|
| 57 | print "$cidr not mastered\n"; | 
|---|
| 58 | } | 
|---|
| 59 | print " done.\n"; | 
|---|
| 60 |  | 
|---|
| 61 | print "Done checking master containment.\n\nChecking block-alignment consistency:\n"; | 
|---|
| 62 |  | 
|---|
| 63 | # Block alignment consistency:  All allocated+free blocks within a master | 
|---|
| 64 | # must NOT overlap, and they must show no gaps. | 
|---|
| 65 | # eg, if we have blocks: | 
|---|
| 66 | #  master is 192.168.2.0/24 | 
|---|
| 67 | #  allocated 192.168.2.0/29, 192.168.2.8/29, 192.168.2.64/26 | 
|---|
| 68 | #  free 192.168.2.16/28, 192.168.2.32/27, 192.168.2.128/25 | 
|---|
| 69 | # then we're OK, but if any one of the allocated or free blocks is missing, | 
|---|
| 70 | # something b0rked. | 
|---|
| 71 |  | 
|---|
| 72 | # (select cidr from allocations where cidr <<= '$master') union | 
|---|
| 73 | #  (select cidr from freeblocks where cidr <<= '$master') | 
|---|
| 74 | #  order by cidr | 
|---|
| 75 |  | 
|---|
| 76 | foreach $master (@masterblocks) { | 
|---|
| 77 | print "Master $master:\n"; | 
|---|
| 78 | ($next,undef) = split /\//, $master; | 
|---|
| 79 | ($last,undef) = split /\//, ($master->broadcast); | 
|---|
| 80 | $sth = $dbh->prepare("(select network(cidr) as net, broadcast(cidr) as bcast ". | 
|---|
| 81 | " from allocations where cidr <<= '$master') union ". | 
|---|
| 82 | "(select network(cidr) as net, broadcast(cidr) as bcast ". | 
|---|
| 83 | "from freeblocks where cidr <<= '$master') order by net"); | 
|---|
| 84 | $sth->execute; | 
|---|
| 85 | while (@data = $sth->fetchrow_array) { | 
|---|
| 86 | ($cur,undef) = split /\//, $data[0]; | 
|---|
| 87 | if ($master !~ /$next/) { | 
|---|
| 88 | ($tmp,undef) = split /\//, $next; | 
|---|
| 89 | @tmp1 = split /\./, $tmp; | 
|---|
| 90 | $tmp1[3]++; | 
|---|
| 91 | if ($tmp1[3] == 256) { $tmp1[3] = 0; $tmp1[2]++; } | 
|---|
| 92 | $cmp = join '.', @tmp1; | 
|---|
| 93 | } else { | 
|---|
| 94 | $cmp = $next; | 
|---|
| 95 | } | 
|---|
| 96 | if ($cur ne $cmp) { | 
|---|
| 97 | print " Gap from $next to $cur\n"; | 
|---|
| 98 | } | 
|---|
| 99 | ($next,undef) = split /\//, $data[1]; | 
|---|
| 100 | } | 
|---|
| 101 | if ($next ne $last) { | 
|---|
| 102 | print " Gap from $next to end of master at $last\n"; | 
|---|
| 103 | } | 
|---|
| 104 | print "done $master.\n"; | 
|---|
| 105 | } | 
|---|