#! /usr/bin/perl

# This code takes 2 "net/len" blocks and joins them together if possible

# Author : Ed Landa (elanda@comstar.net)
# Version : 
#
# Copyright 1997 ComStar Communication, Inc.



if ($ARGV[0])
{
   $blk1=$ARGV[0];
}
else
{
   print "ERROR: No block1\n";
	exit;
}

if ($ARGV[1])
{
   $blk2=$ARGV[1];
}
else
{
   print "ERROR: No block2\n";
	exit;
}

# Parse it up
($ip1,$bits1) = split('/',$blk1);
($a1,$b1,$c1,$d1) = split(/\./,$ip1);

($ip2,$bits2) = split('/',$blk2);
($a2,$b2,$c2,$d2) = split(/\./,$ip2);


# Error check the network numbers

if ($bits1 != $bits2)
{
   print "ERROR: Networks must be of equal size.\n\n";
	exit;
}
else
{
   $bits=$bits1;    # we only need one bits variable now
}


# Error check the splitting
if (($bits > 30) || ($bits < 2))
{
   print "ERROR: It is not possible to join this Network/Mask.\n\n";
	exit;
}


# Check to see which block is 'smaller'

$num1 = (($a1 * (256**3)) + ($b1 * (256**2)) + ($c1 * (256**1)) + $d1);
$num2 = (($a2 * (256**3)) + ($b2 * (256**2)) + ($c2 * (256**1)) + $d2);

if ($num2 < $num1)     # swap the blocks
{
   ($a3,$b3,$c3,$d3)=($a1,$b1,$c1,$d1);
   ($a1,$b1,$c1,$d1)=($a2,$b2,$c2,$d2);
   ($a2,$b2,$c2,$d2)=($a3,$b3,$c3,$d3);
}



# Now check the first block to make sure it falls on the new network boundary
($fa1,$fb1,$fc1,$fd1,$la1,$lb1,$lc1,$ld1) = &unmask($a1,$b1,$c1,$d1,$bits+1);
if ( ($a1, $b1, $c1, $d1) != ($fa1, $fb1, $fc1, $fd1) )
{
   print "ERROR: First network does not fall on new boundary.\n\n";
	exit;
}

# Make a call with the info that was entered
($fa1,$fb1,$fc1,$fd1,$la1,$lb1,$lc1,$ld1) = &unmask($a1,$b1,$c1,$d1,$bits);
($fa2,$fb2,$fc2,$fd2,$la2,$lb2,$lc2,$ld2) = &unmask($a2,$b2,$c2,$d2,$bits);

# Does the returned start-of-block match what was input?
if ( ($a1, $b1, $c1, $d1) != ($fa1, $fb1, $fc1, $fd1) )
{
   print "ERROR: Invalid Network/Mask entered.\n\n";
	exit;
}

if ( ($a2, $b2, $c2, $d2) != ($fa2, $fb2, $fc2, $fd2) )
{
   print "ERROR: Invalid Network/Mask entered.\n\n";
	exit;
}

# Add one to the end of the first block.  Do we get the beginning of the 
# next block?
($a3,$b3,$c3,$d3) = incaddr($la1,$lb1,$lc1,$ld1);

if ( ($a3 != $fa2) || ($b3 != $fb2) || ($c3 != $fc2) || ($d3 != $fd2) )
{
   print "ERROR: networks are not adjacent.\n\n";
	exit;
}

# OK, go with it

$bits--;
print "$a1.$b1.$c1.$d1/$bits\n";
exit;


sub incaddr {
   local ($la, $lb, $lc, $ld) = @_;
	local ($a, $b, $c, $d);

   $a=0+$la; $b=0+$lb; $c=0+$lc; $d=0+$ld;

	$d=$ld+1;
	if ($d>255)
	{
		$d=0;
		$c=$lc+1;
		if ($c>255)
		{
			$c=0;
			$b=$lb+1;
			if ($b>255)
			{
				$b=0;
				$a=$la+1;
				if ($a>255)
				{
					print "ERROR: Error in splitting block.  You should never see this.\n\n";
					exit;
				}
			}
		}
	}
   return($a,$b,$c,$d);
}

# Take a network and mask and return the starting and ending IP addresses
# of that range
sub unmask {
   local ($a, $b, $c, $d, $mask) = @_;

	$add1 = (($a * (256**3)) + ($b * (256**2)) + ($c * (256**1)) + $d);
	$mb = (2**32)-(2**(32-$mask));
	$mb2 = 2**(32-$mask)-1;

	$add2 = ($add1 & $mb);
	$add3 = ($add2 | $mb2);

	($fa,$fb,$fc,$fd) = &unp($add2);
	($la,$lb,$lc,$ld) = &unp($add3);

   return ($fa, $fb, $fc, $fd, $la, $lb, $lc, $ld);
}

# Convert 32 bit IP address to dotted quad
sub unp {
	local($o) = @_[0];
	local($r);
	local($a,$b,$c,$d);

	$d = $o & 0x000000ff;
        $o >>= 8;
	$c = $o & 0x000000ff;
        $o >>= 8;
	$b = $o & 0x000000ff;
        $o >>= 8;
	$a = $o & 0x000000ff;

	return($a,$b,$c,$d);
	}


