#!/usr/bin/perl
#This program is free software: you can redistribute it and/or modify it under the terms
#of the GNU General Public License as published by the Free Software Foundation, either
#version 3 of the license, or any later version.
#This program is distibuted in the hope that it will be useful, but WITHOUT ANY WARRANTY;
#without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#See the GNU General Public License for more details.
#You should have received a copy of the GNU General Public License along with this program.
#If not, see
#To contact the author of this software, send an e-mail to Bill Farley (bill.farley@gmail.com).
#This script is designed to recognize and identify duplicate network blocks and/or overlapping
#subnets from a tab delimited file. It requires that your tab delimited file be in the following format:
#example
#1.1.1.1 255.255.0.0
#2.2.2.2 255.255.255.0
#
#When finished, save your tab-delimited file to the same directory as this script
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
system(clear); #clear user's terminal screen
print "Starting Script........\n\n"; #notify user that script has started
$start = localtime; #timestamp of when script started
$found = 0; #counter to pass information back to the user after script is complete.
#open tab-delimited file and create an array for each line
open(FILE, "<$filename") || die ("Error 103 - Could not open $filename\n");
$line_counter = 0; #counts the number of lines in the file
while () {
chomp $_;
#split the line into array variables for Network and Subnetmask
($network[$line_counter],$subnetmask[$line_counter]) = split(/\t/,$_);
$line_counter++;
}
close(FILE);
&duplicates; #check the network array for duplicate network blocks
print "\n"; #prints a blank line between duplicates and overlaps when displayed back to user
#decriment subnetmask by one bit
$snc = 0;
foreach $network(@network) {
$original_network = $network; #new variable will be used as a reference if any overlapping networks are found
&slashnot; #calls subroutine to convert decimal notation for subnetmask to slash notation
$snc++;
}
#provide user with status of script
if($found gt 0) {
print "\nScript Complete........ Please review the previous warning(s) listed above.\n\n";
}
else {
print "\nScript Complete........ No duplicates or overlaps were found.\n\n";
}
$stop = localtime;
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
sub BEGIN {
system(clear); #clears the user's terminal
print "Subnetoverlap.pl Copyright (C) 2005, 2007 Bill Farley\n\n";
print "This program is free software: you can redistribute it and/or modify it under the terms\n";
print "of the GNU General Public License as published by the Free Software Foundation, either\n";
print "version 3 of the license, or any later version.\n";
print "This program comes with ABSOLUTELY NO WARRANTY.\n\n\n";
print "What is the filename of the tab-delimited file? (Example: file.txt): "; $filename = ;
#open user provided file and remove all extra hidden characters then rewrite to a new file so script will execute properly
$tempfilename = ("$filename" . "temp.txt");
open(TEXT,"<$filename") || die ("Error 101 - Can't open $filename"); #user's file
open(NEW, ">$tempfilename") || die ("Error 102 - Can't open $tempfilename"); #new file that script will use
$text_counter = 0;
while () {
chomp $_;
$_ =~ s/\r\n//g; #checking for extra hidden characters in user's file and variables
$_ =~s/\r//g; #checking for extra hidden characters in user's file and variables
$_ =~s/\n//g; #checking for extra hidden characters in user's file and variables
(($network[$text_counter], ($subnetmask[$text_counter])) = split /\t/,$_); #separating line into two arrays
chomp $network[$text_counter]; chomp $subnetmask[$text_counter]; #removing any newline characters that may be in variables
$text_counter++;
}
close(TEXT);
#write array variables to new file
$text_counter2 = 0;
until ($text_counter2 eq $text_counter) {
print NEW "$network[$text_counter2]\t$subnetmask[$text_counter2]\n"; #writing variables into new file in tab-delimited format
$text_counter2++;
}
close(NEW);
#create a hash that corrolates decimal notation to slash notation
%slash = ("128.0.0.0", 1,"192.0.0.0", 2,"224.0.0.0", 3,"240.0.0.0", 4,"248.0.0.0", 5,"252.0.0.0", 6,"254.0.0.0", 7,"255.0.0.0", 8,"255.128.0.0", 9,"255.192.0.0", 10,"255.224.0.0", 11,"255.240.0.0", 12,"255.248.0.0", 13,"255.252.0.0", 14,"255.254.0.0", 15,"255.255.0.0", 16,"255.255.128.0", 17,"255.255.192.0", 18,"255.255.224.0", 19,"255.255.240.0", 20,"255.255.248.0", 21,"255.255.252.0", 22,"255.255.254.0", 23,"255.255.255.0", 24,"255.255.255.128", 25,"255.255.255.192", 26,"255.255.255.224", 27,"255.255.255.240", 28,"255.255.255.248", 29,"255.255.255.252", 30,"255.255.255.254", 31,"255.255.255.255", 32,);
#create a hash that corrolates slash notation to decimal notation
%decimal = (1, "128.0.0.0",2, "192.0.0.0",3, "224.0.0.0",4, "240.0.0.0",5, "248.0.0.0",6, "252.0.0.0",7, "254.0.0.0",8, "255.0.0.0",9, "255.128.0.0",10, "255.192.0.0",11, "255.224.0.0",12, "255.240.0.0",13, "255.248.0.0",14, "255.252.0.0",15, "255.254.0.0",16, "255.255.0.0",17, "255.255.128.0",18, "255.255.192.0",19, "255.255.224.0",20, "255.255.240.0",21, "255.255.248.0",22, "255.255.252.0",23, "255.255.254.0",24, "255.255.255.0",25, "255.255.255.128",26, "255.255.255.192",27, "255.255.255.224",28, "255.255.255.240",29, "255.255.255.248",30, "255.255.255.252",31, "255.255.255.254",32, "255.255.255.255",);
}
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
sub duplicates {
$avc = 0; #This is a counter for the array variables
foreach $network(@network) {
while ($avc < $line_counter) {
if ($network eq $network[$avc]) { #matching each array variable against all other variables in the array.
$match++; #counter to keep track of the variable matches since the matching variable is from
#from the array, there will always be at least one match against itself.
#Looking for anything higher than a single match to identify a true duplication
if ($match gt 1) {
print "WARNING!! There is a duplicate network match for $network.\n";
$found++;
}
}
$avc++;
}
$avc = 0;
$match = 0;
}
}
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
sub slashnot {
foreach $key (keys(%slash)) {
if ($key eq $subnetmask[$snc]) {
$new_slash = ($slash{$subnetmask[$snc]} - 1); #decrimenting subnetmask of original subnetmask by one bit
&decimalnot; #calling subroutine to change new slash notation back to decimal notation
}
}
}
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
sub decimalnot {
foreach $key (keys(%decimal)) {
if ($key eq $new_slash) {
$new_subnetmask = $decimal{$key}; #converting slash notation to decimal notation
&binaryand; #calling subroutine to identify new network block address
}
}
}
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
sub binaryand {
($ipoctet1,$ipoctet2,$ipoctet3,$ipoctet4) = split(/\./,$network); #split up the network block and assign octet variables
($snmoctet1,$snmoctet2,$snmoctet3,$snmoctet4) = split(/\./,$new_subnetmask); #split up the subnetmask and assign octet variables
#Due to a bug in Perl, after the split, the new variables need to have an mathmatical operation
#performed in order to make them numeric variables rather than string variables.
$num_con1 = $snmoctet1 + $ipoctet1;
$num_con2 = $snmoctet2 + $ipoctet2;
$num_con3 = $snmoctet3 + $ipoctet3;
$num_con4 = $snmoctet4 + $ipoctet4;
#identify the network block address by "AND"ing the ip address and the subnet mask.
$nwoctet1 = $snmoctet1 & $ipoctet1;
$nwoctet2 = $snmoctet2 & $ipoctet2;
$nwoctet3 = $snmoctet3 & $ipoctet3;
$nwoctet4 = $snmoctet4 & $ipoctet4;
$new_network = ("$nwoctet1.$nwoctet2.$nwoctet3.$nwoctet4"); #joining octets together into a single variable
$new_subnetmask = ("$snmoctet1.$snmoctet2.$snmoctet3.$snmoctet4"); #joining octets together into a single variable
&overlap; #calling subroutine to identfy any overlappping networks
}
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
sub overlap {
$overlap_counter = 0;
while($overlap_counter < $line_counter) {
#match new subnet against all other variables in the array
if (($new_network eq $network[$overlap_counter]) and ($new_subnetmask eq $subnetmask[$overlap_counter])) {
print "WARNING!! There is an overlap between $new_network and $original_network\n";
$found++;
}
$overlap_counter++;
}
#continue to decriment subnetmask by one bit until subnetmask is a /1
if ($new_slash ne 1) {
$new_slash--; #decrimenting subnetmask slash notation by one bit
&decimalnot; #looping to subroutine for conversion back to decimal notation
}
}