Howdy all.
I had an assignment to build a subnet calculator that would take (and validate) an IP and CIDR input and return the net_id, broadcast_id, first and last assignable IP addresses, and the number of assignable IP address.
Would anyone care to look at my code and offer criticism?
Thank you.
#! c:\perl -w
system("pause"); ## to allow viewing of warnings
do ## loop allows user to perform another calculation
{ system("cls");
$doagain = ""; @bin_octets =(); @bin_subnet_mask = (); ## initialize values
do ## loops until IP is valid
{ $valid = 0;
print "\n--------------------------------------------------------------------------\n";
print "\nThis program will calculate the network ID and broadcast ID, first and \nlast assignable IP address, and number of assignable IP addresses based \non the IP address and CIDR you input.";
print "\n\nEnter your IP address and CIDR (e.g. 192.168.2.1/28): ";
chomp($input = <STDIN>);
if ($input =~ /^(22[0-3]|2[0-1][0-9]|1[0-9][0-9]|0?[1-9][0-9]|0{0,2}[1-9])\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(0?30|0?[12][0-9]|0?0?[89])$/)
{ for ($x = 1; $x < 5; $x++)
{ ${"oct$x"} = ${"$x"}; }
$cidr = $5;
$valid = 1; ## increment $valid to get out of while loop
}
else { print "\n\nInvalid IP or CIDR. Please try again.\n"; }
} while ($valid ne 1);
for ($x = 1; $x < 5; $x++) ## convert octets to binary
{ @bin_octets = (@bin_octets, dec_2_bin(${"oct$x"})); }
for ($x = 1; $x <= $cidr; $x++) ## Build binary subnet mask from CIDR
{ @bin_subnet_mask = (@bin_subnet_mask, 1); }
for ($x = $cidr + 1; $x <= 32; $x++)
{ @bin_subnet_mask = (@bin_subnet_mask, 0); }
for ($x = 0; $x < 32; $x++)
{ $bin_net_id[$x] = $bin_octets[$x] & $bin_subnet_mask[$x]; ## AND mask with octets to find Net_id
$bin_broadcast[$x] = $bin_octets[$x] | !$bin_subnet_mask[$x]; ## OR octets with mask inverse to find broadcast_id
}
for ($i=1; $i<=4; $i++) ## split the 32-bit binary arrays into 4 8-bit arrays and then convert to decimal
{ @{"bin_net_id$i"} = split32($i, @bin_net_id);
${"net_id$i"} = bin_2_dec(@{"bin_net_id$i"});
@{"bin_broadcast$i"} = split32($i, @bin_broadcast);
${"broadcast$i"} = bin_2_dec(@{"bin_broadcast$i"});
}
print "\nReady for the results? "; system("pause"); system("cls"); ## print results
print "\n--------------------------------------------------------------------------\n";
print "\n\tOriginal IP address and CIDR: \t\t$oct1.$oct2.$oct3.$oct4/$cidr";
printf("\n\tNumber of assignable IP addresses: \t%d", 2**(32-$cidr)-2);
print "\n\tNetwork ID: \t\t\t\t$net_id1.$net_id2.$net_id3.$net_id4/$cidr";
printf("\n\tFirst assignable IP: \t\t\t%d.%d.%d.%d/%d", $net_id1,$net_id2,$net_id3,$net_id4+1,$cidr);
printf("\n\tLast assignable IP: \t\t\t%d.%d.%d.%d/%d", $broadcast1,$broadcast2,$broadcast3,$broadcast4-1,$cidr);
print "\n\tBroadcast address: \t\t\t$broadcast1.$broadcast2.$broadcast3.$broadcast4/$cidr\n";
print "\n--------------------------------------------------------------------------\n";
print "\nHit 'Y' if you would you like to calculate another subnet: ";
chomp($doagain = <STDIN>);
} while ($doagain eq "y" or $doagain eq "Y");
print "\nQuitting ...\n";
########################## SUB FUNCTIONS ##########################
sub dec_2_bin ## to convert a decimal number into an 8-bit binary array
{ split (//, sprintf("%08b", @_), 8); }
sub bin_2_dec ## to convert a binany number into a decimal number
{ oct("0b" . join("",@_)); }
sub split32 ## used (along with a 'for' loop), to split a 32-bit binary string into 4 8-bit strings
{ my ($a, @b) = @_;
my $joined = join("",@b);
if ($joined =~ /([01]{8})([01]{8})([01]{8})([01]{8})/)
{ ${"$a"}; }
}