#!/usr/bin/perl

# cidrmath script - by Ken P. Chase math att sizone dott org
#
# this script will return all remaining largest CIDR netblocks given some to
#  add/remove from a larger list. negative blocks removed from existing
#  blocks 
#
# feel free to modify, copy or otherwise distribute this code, try to
#  keep my name on it, drop me a line via email if you like it/find it
#  useful.
#
# need the Net::Netmask perl module, libnet-netmask-perl in debian
#
# this is version 0.10 beta Oct 2006
#
# (CC) BY-NC-SA 2016 https://creativecommons.org/licenses/by-nc-sa/4.0/
#

(! $ARGV[2]) && 
  (print "$0 (CC) 2006 / (CC BY-NC-SA 2016) by Ken P. Chase  math@sizone.org
Usage: $0 (block1) (+/-) (block2) [ (+/-) (block3) [ (+/-) (block4) .. ] ]

 for all CIDR blocks (in x.x.x.x/y netmask notation) will +add/-remove
 blocks from block1 and return all largest blocks in result.

 Note: removing a block outside the main block wont create a negative
       block for further operations. 

  ie: b not in a:  a - b + b   gives  a + b cuz b cant be removed from a
				      if b isnt in a.
      but          a + b - b   gives  a, as b exists after + b is executed.

 Note: cidrmasks crossing net boundaries will map into the netblock of the 
       host part of the network: ie: 10.0.0.8/28 will evaluate as 10.0.0.0/28

 WARNING: This can run extremely slowly w/tons of ram for huge networks...\n") &&
  (exit);
 
use Net::Netmask;

$block = new Net::Netmask ($ARGV[0]);
shift;

for $net ($block->enumerate) {
   $tmpblock = new Net::Netmask ($net);
   $tmpblock->storeNetblock;
}

while ($ARGV[1]) {
  $op = $ARGV[0]; shift;
  $block_op = new Net::Netmask ($ARGV[0]); shift;
  
  for $net ($block_op->enumerate) {
     $tmpblock = new Net::Netmask ($net);
     if ($op eq "-") { $tmpblock->deleteNetblock }
     else {$tmpblock->storeNetblock};
  }
}

print join("\n", cidrs2cidrs(dumpNetworkTable)), "\n";
  
  
