Advertisement
Guest User

openspace.pl

a guest
Nov 2nd, 2015
605
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 6.05 KB | None | 0 0
  1. #!/usr/bin/perl
  2.  
  3. ### Show list of used/unused subnets in a given supernet
  4. ###
  5. ### Usage ./openspace.pl [<username>@]<router_addresss> <supernet>
  6.  
  7. use strict;
  8. use Net::OpenSSH;
  9. use Term::ReadKey;
  10. use Net::CIDR;
  11. use Term::ANSIColor;
  12.  
  13. my $router;
  14. my $user;
  15.  
  16. ### Validate argument count
  17. if (@ARGV != 2) {
  18.   print "Usage ./openspace.pl [<username>@]<router_addresss> <supernet>\n";
  19.   exit;
  20. }
  21.  
  22. ### Unbuffer STDOUT so we can tee and watch this live
  23. $|=1;
  24.  
  25. ### First argument may include username; handle that
  26. if ($ARGV[0] =~ /\@/) {
  27.   my @ssh_info = split ('@', $ARGV[0]);
  28.   $user = $ssh_info[0];
  29.   $router = $ssh_info[1];
  30. } else {
  31.   $user = $ENV{LOGNAME} || $ENV{USER} || getpwuid($<);
  32.   $router = $ARGV[0];
  33. }
  34.  
  35. my $supernet = $ARGV[1]; ### Supernet to break down subnet usage
  36. my @subnets = (); ### Array to hold used subnets
  37.  
  38. ### Get user's password
  39. print STDERR "Password ($user): ";
  40. ReadMode('noecho');
  41. chomp(my $pass = ReadLine(0));
  42. print STDERR "\n";
  43. ReadMode('restore');
  44.  
  45. ### SSH to router
  46. my $ssh = Net::OpenSSH->new($user.":".$pass."@".$router, master_stderr_discard => 1, master_opts => [-o => "StrictHostKeyChecking=no"]);
  47. $ssh->error and
  48. die "Couldn't establish SSH connection to $user"."@"."$router:\n".$ssh->error;
  49.  
  50. ### Get routes in given supernet
  51. chomp(my @routes = $ssh->capture("show route $supernet | grep ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/ | except \/32"));
  52.  
  53. ### If there are no routes, print the supernet in green and exit
  54. if (!@routes) {
  55.   print color('green');
  56.   print "$supernet\n";
  57.   print color('reset');
  58.   exit;
  59. }
  60.  
  61. ### Trim the routes to grab just the subnets
  62. foreach (@routes) {
  63.   if ($_ =~ /(^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2})/) {
  64.     push (@subnets, $1);
  65.   }
  66. }
  67.  
  68. ### Deduplicate the list of subnets
  69. my %dedupe = map { $_ => 1 } @subnets;
  70. my @subnets = keys %dedupe;
  71.  
  72. ### Sort the subnets
  73. my @sorted_subnets = ();;
  74. @sorted_subnets = sort {
  75.   my @a = $a =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
  76.   my @b = $b =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
  77.   $a[0] <=> $b[0] ||
  78.   $a[1] <=> $b[1] ||
  79.   $a[2] <=> $b[2] ||
  80.   $a[3] <=> $b[3] ||
  81.   $a[4] <=> $b[4]
  82. } @subnets;
  83.  
  84. ### Find any subnets that appear to be aggregates
  85. my @aggregate_subnets = ();
  86. for (my $i = 0; $i < @sorted_subnets-1; $i++) {
  87.   ### Find out the first and last IP in the next element's range
  88.   my @range = Net::CIDR::cidr2range($sorted_subnets[$i+1]);
  89.   my @endpoints = split('-', $range[0]);
  90.   my @cidr_list = ();
  91.   $cidr_list[0] = $sorted_subnets[$i];
  92.   if (Net::CIDR::cidrlookup($endpoints[0], @cidr_list) && Net::CIDR::cidrlookup($endpoints[1], @cidr_list)) {
  93.     print color('red');
  94.     print "### NOTICE: $sorted_subnets[$i] overlaps $sorted_subnets[$i+1] and is marked as aggregate.\n";
  95.     print color('reset');
  96.     push (@aggregate_subnets, $sorted_subnets[$i]);
  97.   }
  98. }
  99.  
  100. ### Remove @aggregate_subnets from @sorted_subnets
  101. %dedupe = ();
  102. $dedupe{$_}=1 foreach (@aggregate_subnets);
  103. @sorted_subnets = grep { not exists $dedupe{$_} } @sorted_subnets;
  104.  
  105. ###DEBUG
  106. #print "SORTED: @sorted_subnets\n";
  107. #print "AGGREGATE: @aggregate_subnets\n";
  108.  
  109. ### Get the start/end addresses to report on
  110. my @range = Net::CIDR::cidr2range($supernet);
  111. my @endpoints = split('-', $range[0]);
  112. my $supernet_start = $endpoints[0];
  113. my $supernet_end = $endpoints[1];
  114. my $supernet_start_in_subnets =  Net::CIDR::cidrlookup($supernet_start, @sorted_subnets);
  115. my $supernet_end_in_subnets = Net::CIDR::cidrlookup($supernet_end, @sorted_subnets);
  116.  
  117. my %results = (); ### Hash to hold results with key being the subnet
  118.                   ### and the value being red (used), yellow (part of supernet), green (available)
  119.  
  120. ###  Add first range of available subnets to %results if first IP in $supernet is not in @sorted_subnets
  121. if (!$supernet_start_in_subnets) {
  122.   my $start = $supernet_start;
  123.   my @split_end = split (/\//,$sorted_subnets[0]);
  124.   my $end = $split_end[0];
  125.   my @gap_subnets = Net::CIDR::range2cidr("$start-$end");
  126.   @gap_subnets = grep { $_ !~ /\/32/ } @gap_subnets;
  127.   foreach my $gap_subnet (@gap_subnets) {
  128.     if (Net::CIDR::cidrlookup($gap_subnet, @aggregate_subnets)) {
  129.       $results{$gap_subnet} = "yellow";
  130.     } else {
  131.       $results{$gap_subnet} = "green";
  132.     }
  133.   }
  134. }
  135.  
  136. ### Add other ranges
  137. for (my $i = 0; $i < @sorted_subnets; $i++) {
  138.   $results{$sorted_subnets[$i]} = "red";
  139.   if (defined ($sorted_subnets[$i+1])) {
  140.     my @range = Net::CIDR::cidr2range($sorted_subnets[$i]);
  141.     my @endpoints = split('-', $range[0]);
  142.     my $start = @endpoints[1];
  143.     @range = Net::CIDR::cidr2range($sorted_subnets[$i+1]);
  144.     @endpoints = split('-', $range[0]);
  145.     my $end = @endpoints[0];
  146.     my @gap_subnets=Net::CIDR::range2cidr("$start-$end");
  147.     @gap_subnets = grep { $_ !~ /\/32/ } @gap_subnets;
  148.     foreach my $gap_subnet (@gap_subnets) {
  149.       if (Net::CIDR::cidrlookup($gap_subnet, @aggregate_subnets)) {
  150.         $results{$gap_subnet} = "yellow";
  151.       } else {
  152.         $results{$gap_subnet} = "green";
  153.       }
  154.     }
  155.   }
  156. }  
  157.  
  158. ### Add last range if last IP in $supernet is not in @sorted_subnets
  159. if (!$supernet_end_in_subnets) {
  160.   my @range = Net::CIDR::cidr2range($sorted_subnets[-1]);
  161.   my @endpoints = split('-', $range[0]);
  162.   my $last_subnet_end = @endpoints[1];
  163.   my @gap_subnets = Net::CIDR::range2cidr("$last_subnet_end-$supernet_end");
  164.   @gap_subnets = grep { $_ !~ /\/32/ } @gap_subnets;
  165.   foreach my $gap_subnet (@gap_subnets) {
  166.     if (Net::CIDR::cidrlookup($gap_subnet, @aggregate_subnets)) {
  167.       $results{$gap_subnet} = "yellow";
  168.     } else {
  169.       $results{$gap_subnet} = "green";
  170.     }
  171.   }
  172. }
  173.  
  174. ### Print the sorted hash
  175. for my $subnet (sort {  
  176.                   my @a = $a =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
  177.                   my @b = $b =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
  178.                   $a[0] <=> $b[0] ||
  179.                   $a[1] <=> $b[1] ||
  180.                   $a[2] <=> $b[2] ||
  181.                   $a[3] <=> $b[3] ||
  182.                   $a[4] <=> $b[4]
  183.                 } (keys %results)) {
  184.   print color($results{$subnet});
  185.   print "$subnet\n";
  186.   print color('reset');
  187. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement