#       checkreg - check overlapping alloactions in reg
#
# Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999 by RIPE NCC
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of the author not be
# used in advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
# AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# $Id: checkreg.pl,v 2.5 1999/10/06 16:41:00 marek Exp $
#
#	$RCSfile: checkreg.pl,v $
#	$Revision: 2.5 $
#	$Author: marek $
#	$Date: 1999/10/06 16:41:00 $

require "getopts.pl";

require "rconf.pl";
require "misc.pl";
require "net2net.pl";
require "dpr.pl";

$REGDIR="/ncc/registries";

# $REGDIR="/home/david/db.test/regdata";


$TESTMAX=25;

local($conffile) = $ENV{"RIPEDBCNF"};
$conffile = $RIPEConfig{DEFCONFIG} unless $conffile;

&rconf($conffile);

&Getopts("v");

#
# main program


my($file,$line,$code,$range);

my($total)=0;

%regdata=();
%regallocdata=();
%regerrordata=();

#&dpr("Reading data ...\n");

$REGDIR.="\/" if ($REGDIR!~ /\/$/);

opendir(DIR, $REGDIR);

foreach $file (readdir(DIR)) {
   
   next if ((!(($file=~ /^(\S\S)\./) && ($COUNTRY{$1}))) || (! -f $REGDIR.$file) || (-d $REGDIR.$file));
   
   $total++;
   
   # next if ($total>$TESTMAX);
   
   open(REG, "<".$REGDIR.$file);
   
   foreach $line (<REG>) {
      
      if ($line=~ s/^allocated\:\s*//) {
         
         # print  "alloc\n";
         
         if (($line=~ /(^|[^\d])([\d\.]+\s*\/\s*\d+)($|[^\d])/) ||
             ($line=~ /(^|[^\d])([\d\.]+\s*\-\s*[\d\.]+)($|[^\d])/)) {
             
            # print  "***\n"; 
             
            ($range,$code)=&normalizerange($2, "");
            
         }
         else {
            $code=$O_SYNTAXERROR;
         }
         
         if ($code==$O_OK) {
            
            if ($line=~ /RETURNED\s+(PA|PI|UNSPECIFIED)/i) {
            
               $regallocdata{$file}.="***skipped*** (returned address space): allocated: ".$line;
               $regdata{$data}.="\n";
            
            }
            else {
            
               $regallocdata{$file}.="allocated: ".$line;
            
               $range=~ /^(\S+)\s*\-\s*(\S+)$/;
            
               $ip1=$1;
               $ip2=$2;
            
               $ip1=&quad2int($ip1,0);
               $ip2=&quad2int($ip2,0);
            
               if ($regdata{$file}) {
            
                  $regdata{$file}=join("\n", $regdata{$file}, $ip1.":".$ip2);
            
               }
               else {
            
                  $regdata{$file}=$ip1.":".$ip2;
            
               }
            
            }
            
         }
         else {
            
            $regerrordata{$file}.="$code:allocated: $line";
            
            $regallocdata{$file}=join("\n", $regdata{$file}, "***skipped*** (due to syntax error): ".$line);
            $regdata{$data}.="\n";
            
         }
         
      }
       
   }
   
   close(REG);
   
}

close(DIR);



%overlap=();
%copyregdata=%regdata;

&dpr("Checking for overlapping allocations ...\n");

my($nr,$y1,$y2,$against);

$total=0;

$against=0;

$|=1;

while (($reg,$data)=each(%regdata)) {
   
   # print "\nAllocated for: ", $reg, "\n\n", $data, "\n"; 
   
   $total++;
   
   # next if ($total>$TESTMAX);
   
#   &dpr("Check $reg ($total) ...\n");
   
   $against=0;
   
   $y1=0;
   
   foreach (split(/\n/,$data)) {
      
      $y1++;
      
      next if (!$_);
      
      ($r1,$r2)=split(":", $_);
      
      # print  "check $reg:\n$r1 <--> $r2\n";
      
      while (($reg2,$data2)=each(%copyregdata)) {
         
         next if ($reg eq $reg2);
      
         $against++;
      
         $y2=0;
         
         foreach (split(/\n/,$data2)) {
         
            $y2++;
            
            next if (!$_);
            
            ($ip1,$ip2)=split(":", $_);
         
            # print  "$ip1 <--> $r1 $ip2 <--> $r2\n";
         
            if (($ip1>=$r1) && ($ip1<=$r2) ||
                ($ip2>=$r1) && ($ip2<=$r2)) {
               
               # print  " $reg: $r1 <--> $r2 $reg2: $ip1 <--> $ip2\n";
               
               if ($overlap{$reg,$reg2}) {
                  
                  $overlap{$reg,$reg2}=join("\n", $overlap{$reg,$reg2}, $y1.":".$y2);
               
               }
               else {
               
                  $overlap{$reg,$reg2}=$y1.":".$y2;
                  
               }
            
            }
         
         }
         
      }
      
   }
   
   #
   # we don't want to check a registry again...
   
   delete($copyregdata{$reg});
   
#   &dpr(" done (checked against ", $against/$y1, " registries)\n");
   
}

#&dpr("Checked $total registries\n\n");


print STDERR "Syntax error(s):\n\n" if (%regerrordata);

my($tmp);

while (($reg,$data)=each(%regerrordata)) {
   
   foreach (split("\n", $data)) {
      
      ($tmp, $nr, $data)=split(/^(\d+)\:/, $data);
   
      print STDERR "Error ($nr) in line (", $reg, "):\n", $data, "\n"; 
   
   }
   
}



my(@errorlist1,@errorlist2);

while (($reg,$data)=each(%overlap)) {
   
   ($reg,$reg2)=split($;, $reg);
   
   @errorlist1=();
   @errorlist2=();
   
   $nr=0;
   
   foreach (split(/\n/, $data)) {
      
      ($y1,$y2)=split(":", $_);
      
      $nr++;
      
      if ($errorlist1[$y1]) {
         $errorlist1[$y1]="*";
      }
      else {
         $errorlist1[$y1]=$nr;
      }
      
      if ($errorlist2[$y2]) {
         $errorlist2[$y2]="*";
      }
      else {
         $errorlist2[$y2]=$nr;
      }
        
   }
   
   print STDERR "Overlapping allocations:\n\nin ", $reg, ":\n\n";
   
   $y1=0;
   
   foreach (split("\n", $regallocdata{$reg})) {
      
      $y1++;
      
      printf STDERR "%3s %s\n", $errorlist1[$y1]?$errorlist1[$y1]."\>":"", $_;
   
   }
   
   print STDERR "\nand ", $reg2, ":\n\n";
   
   $y2=0;
   
   foreach (split("\n", $regallocdata{$reg2})) {
      
      $y2++;
      
      printf STDERR "%3s %s\n", $errorlist2[$y2]?$errorlist2[$y2]."\>":"", $_;
   
   }
   
   print STDERR "\n\n";
   
}

#&dpr("Building list of allocated address space...\n");

my(@allocated);

@allocations=();

while (($reg,$data)=each(%regdata)) {
   
   foreach (split(/\n/, $data)) {
   
      next if (!$_);
      
      push(@allocations, $_.":".$reg);
      
   }   
     
}

#&dpr("Sorting list of allocated address space...\n");


@allocations=sort {
       
                    ($ip1)= $a=~ /^(\d+)\:/;
   
                    $b=~ /^(\d+)\:/;
   
                    $ip1 <=> $1; 

                  } @allocations;


#&dpr("Building lists of free and allocated address space...\n");

open(FREE, ">FREE");
open(ALLOC, ">ALLOC");
open(ALL, ">ALL");

my($ip1old,$ip2old);

$ip2old=&quad2int("255.255.255.254",0);

while (@allocations) {
   
   ($ip1,$ip2,$reg)=split(/\:/, shift(@allocations));   
   
   # print "$ip1 - $ip2";
   # print &old_to_new("0.0.0.0 - 0.0.0.255");
   
   $newalloc=join(", ", &old_to_new(&int2quad($ip1)." - ".&int2quad($ip2))); 
   
   if ($ip1>($ip2old+1)) {
      $newfree=join(", ", &old_to_new(&int2quad($ip2old+1)." - ".&int2quad($ip1-1)));
   }
   else {
      $newfree="";
   }
   
   print FREE $newfree, "\n" if ($newfree);
   print ALL "FREE:                      ", $newfree, "\n" if ($newfree);
   
   printf ALLOC "%19s %s\n", $newalloc, $reg; 
   printf ALL "ALLOCATED to %12.12s: %s\n", $reg, $newalloc; 
      
   $ip1old=$ip1;
   $ip2old=$ip2;  
   
}

close(FREE);
close(ALLOC);
close(ALL);

print "program completed.\n" if ($opt_v);

# en of checkreg
