Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- ### Show list of used/unused subnets in a given supernet
- ###
- ### Usage ./openspace.pl [<username>@]<router_addresss> <supernet>
- use strict;
- use Net::OpenSSH;
- use Term::ReadKey;
- use Net::CIDR;
- use Term::ANSIColor;
- my $router;
- my $user;
- ### Validate argument count
- if (@ARGV != 2) {
- print "Usage ./openspace.pl [<username>@]<router_addresss> <supernet>\n";
- exit;
- }
- ### Unbuffer STDOUT so we can tee and watch this live
- $|=1;
- ### First argument may include username; handle that
- if ($ARGV[0] =~ /\@/) {
- my @ssh_info = split ('@', $ARGV[0]);
- $user = $ssh_info[0];
- $router = $ssh_info[1];
- } else {
- $user = $ENV{LOGNAME} || $ENV{USER} || getpwuid($<);
- $router = $ARGV[0];
- }
- my $supernet = $ARGV[1]; ### Supernet to break down subnet usage
- my @subnets = (); ### Array to hold used subnets
- ### Get user's password
- print STDERR "Password ($user): ";
- ReadMode('noecho');
- chomp(my $pass = ReadLine(0));
- print STDERR "\n";
- ReadMode('restore');
- ### SSH to router
- my $ssh = Net::OpenSSH->new($user.":".$pass."@".$router, master_stderr_discard => 1, master_opts => [-o => "StrictHostKeyChecking=no"]);
- $ssh->error and
- die "Couldn't establish SSH connection to $user"."@"."$router:\n".$ssh->error;
- ### Get routes in given supernet
- 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"));
- ### If there are no routes, print the supernet in green and exit
- if (!@routes) {
- print color('green');
- print "$supernet\n";
- print color('reset');
- exit;
- }
- ### Trim the routes to grab just the subnets
- foreach (@routes) {
- if ($_ =~ /(^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2})/) {
- push (@subnets, $1);
- }
- }
- ### Deduplicate the list of subnets
- my %dedupe = map { $_ => 1 } @subnets;
- my @subnets = keys %dedupe;
- ### Sort the subnets
- my @sorted_subnets = ();;
- @sorted_subnets = sort {
- my @a = $a =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
- my @b = $b =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
- $a[0] <=> $b[0] ||
- $a[1] <=> $b[1] ||
- $a[2] <=> $b[2] ||
- $a[3] <=> $b[3] ||
- $a[4] <=> $b[4]
- } @subnets;
- ### Find any subnets that appear to be aggregates
- my @aggregate_subnets = ();
- for (my $i = 0; $i < @sorted_subnets-1; $i++) {
- ### Find out the first and last IP in the next element's range
- my @range = Net::CIDR::cidr2range($sorted_subnets[$i+1]);
- my @endpoints = split('-', $range[0]);
- my @cidr_list = ();
- $cidr_list[0] = $sorted_subnets[$i];
- if (Net::CIDR::cidrlookup($endpoints[0], @cidr_list) && Net::CIDR::cidrlookup($endpoints[1], @cidr_list)) {
- print color('red');
- print "### NOTICE: $sorted_subnets[$i] overlaps $sorted_subnets[$i+1] and is marked as aggregate.\n";
- print color('reset');
- push (@aggregate_subnets, $sorted_subnets[$i]);
- }
- }
- ### Remove @aggregate_subnets from @sorted_subnets
- %dedupe = ();
- $dedupe{$_}=1 foreach (@aggregate_subnets);
- @sorted_subnets = grep { not exists $dedupe{$_} } @sorted_subnets;
- ###DEBUG
- #print "SORTED: @sorted_subnets\n";
- #print "AGGREGATE: @aggregate_subnets\n";
- ### Get the start/end addresses to report on
- my @range = Net::CIDR::cidr2range($supernet);
- my @endpoints = split('-', $range[0]);
- my $supernet_start = $endpoints[0];
- my $supernet_end = $endpoints[1];
- my $supernet_start_in_subnets = Net::CIDR::cidrlookup($supernet_start, @sorted_subnets);
- my $supernet_end_in_subnets = Net::CIDR::cidrlookup($supernet_end, @sorted_subnets);
- my %results = (); ### Hash to hold results with key being the subnet
- ### and the value being red (used), yellow (part of supernet), green (available)
- ### Add first range of available subnets to %results if first IP in $supernet is not in @sorted_subnets
- if (!$supernet_start_in_subnets) {
- my $start = $supernet_start;
- my @split_end = split (/\//,$sorted_subnets[0]);
- my $end = $split_end[0];
- my @gap_subnets = Net::CIDR::range2cidr("$start-$end");
- @gap_subnets = grep { $_ !~ /\/32/ } @gap_subnets;
- foreach my $gap_subnet (@gap_subnets) {
- if (Net::CIDR::cidrlookup($gap_subnet, @aggregate_subnets)) {
- $results{$gap_subnet} = "yellow";
- } else {
- $results{$gap_subnet} = "green";
- }
- }
- }
- ### Add other ranges
- for (my $i = 0; $i < @sorted_subnets; $i++) {
- $results{$sorted_subnets[$i]} = "red";
- if (defined ($sorted_subnets[$i+1])) {
- my @range = Net::CIDR::cidr2range($sorted_subnets[$i]);
- my @endpoints = split('-', $range[0]);
- my $start = @endpoints[1];
- @range = Net::CIDR::cidr2range($sorted_subnets[$i+1]);
- @endpoints = split('-', $range[0]);
- my $end = @endpoints[0];
- my @gap_subnets=Net::CIDR::range2cidr("$start-$end");
- @gap_subnets = grep { $_ !~ /\/32/ } @gap_subnets;
- foreach my $gap_subnet (@gap_subnets) {
- if (Net::CIDR::cidrlookup($gap_subnet, @aggregate_subnets)) {
- $results{$gap_subnet} = "yellow";
- } else {
- $results{$gap_subnet} = "green";
- }
- }
- }
- }
- ### Add last range if last IP in $supernet is not in @sorted_subnets
- if (!$supernet_end_in_subnets) {
- my @range = Net::CIDR::cidr2range($sorted_subnets[-1]);
- my @endpoints = split('-', $range[0]);
- my $last_subnet_end = @endpoints[1];
- my @gap_subnets = Net::CIDR::range2cidr("$last_subnet_end-$supernet_end");
- @gap_subnets = grep { $_ !~ /\/32/ } @gap_subnets;
- foreach my $gap_subnet (@gap_subnets) {
- if (Net::CIDR::cidrlookup($gap_subnet, @aggregate_subnets)) {
- $results{$gap_subnet} = "yellow";
- } else {
- $results{$gap_subnet} = "green";
- }
- }
- }
- ### Print the sorted hash
- for my $subnet (sort {
- my @a = $a =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
- my @b = $b =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
- $a[0] <=> $b[0] ||
- $a[1] <=> $b[1] ||
- $a[2] <=> $b[2] ||
- $a[3] <=> $b[3] ||
- $a[4] <=> $b[4]
- } (keys %results)) {
- print color($results{$subnet});
- print "$subnet\n";
- print color('reset');
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement