Adding SubnetCalculator Goodie

master
Rob 2013-09-15 18:17:43 +01:00
parent c57db32c1c
commit 7f209020c9
2 changed files with 119 additions and 0 deletions

91
lib/DDG/Goodie/SubnetCalc.pm Executable file
View File

@ -0,0 +1,91 @@
#!/bin/env perl
package DDG::Goodie::SubnetCalc;
# ABSTRACT: Calculate IP ranges & Subnet Information from a host & CIDR or netmask
use strict;
use warnings;
use DDG::Goodie;
# TODO: This (sh|c)ould be re-written to be more precise
triggers query => qr`^([0-9]{1,3}\.){3}([0-9]{1,3})[\s/](([1-3]?[0-9])|(([0-9]{1,3}\.){3}([0-9]{1,3})))$`;
zci answer_type => "subnet_info";
zci is_cached => 1;
attribution github => ['https://github.com/mintsoft', 'mintsoft'];
primary_example_queries '10.1.2.3/25';
secondary_example_queries '46.51.197.88/255.255.254.0', '176.34.131.233/32';
category 'computing_tools';
topics 'sysadmin';
handle query => sub {
sub ip2str($) {
my ($ip) = @_;
return sprintf "%u.%u.%u.%u", ($ip>>24&0xff),($ip>>16&0xff),($ip>>8&0xff),($ip&0xff);
}
sub array2long(@) {
return (int($_[0])<<24) + (int($_[1])<<16) + (int($_[2])<<8) + (int($_[3]));
}
my ($input) = @_;
my ($address,$cidr) = split qr`[\s/]`, $input;
my @octlets = split /\./,$address;
for (@octlets) {
return if int($_)>255;
}
my $addressRaw = array2long(@octlets);
my $cidrHostMaskRaw = 0;
my $cidrRaw = 0;
# Convert CIDR & Subnets
if ($cidr =~ /^[0-9]+$/) {
return if ($cidr>32 || $cidr<1);
$cidrHostMaskRaw = 2**(32-$cidr)-1;
$cidrRaw = 0xffffffff ^ $cidrHostMaskRaw;
}
elsif ($cidr =~ /([0-9]{1,3}\.){3}([0-9]{1,3})/) {
my @cidr_octlets = split /\./,$cidr;
for(@cidr_octlets) {
return if int($_)>255;
}
$cidrRaw = array2long(@cidr_octlets);
my $cidrBinary = sprintf("%b",$cidrRaw);
return unless ($cidrBinary =~ /^1+0*$/);
$cidrHostMaskRaw = 0xffffffff ^ $cidrRaw;
$cidr = ($cidrBinary =~ tr/1//); #count number of 1's
}
else {
return;
}
my $host = $addressRaw & $cidrHostMaskRaw;
my $network = $addressRaw & $cidrRaw;
my $start = $network+1;
my $end = $network+($cidrHostMaskRaw-1);
my $broadcast = $network+$cidrHostMaskRaw;
my $hostCount = 1+$end-$start;
my $whichSpecified = "Host #".($host);
$whichSpecified = "Network" if ($host==0);
$whichSpecified = "Broadcast" if ($host==$hostCount+1);
$whichSpecified = "Point-To-Point (".ip2str($end).", ".ip2str($start).")" if ($cidr==31);
$whichSpecified = "Host Only" if ($cidr==32);
my $outputStr = "Network: ".ip2str($network)."/$cidr,".
" Netmask: ".ip2str($cidrRaw).",".
" $whichSpecified specified";
$outputStr .= ", Host Address Range: ".ip2str($start)."-".ip2str($end).",".
" $hostCount Usable Addresses,".
" Broadcast: ".ip2str($broadcast)
unless($cidr > 30);
return $outputStr;
};
1;

28
t/SubnetCalc.t Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;
zci answer_type => 'subnet_info';
zci is_cached => 1;
ddg_goodie_test(
[
# This is the name of the goodie that will be loaded to test.
'DDG::Goodie::SubnetCalc'
],
"10.0.0.0/24" => test_zci("Network: 10.0.0.0/24, Netmask: 255.255.255.0, Network specified, Host Address Range: 10.0.0.1-10.0.0.254, 254 Usable Addresses, Broadcast: 10.0.0.255"),
"192.168.0.0/24" => test_zci("Network: 192.168.0.0/24, Netmask: 255.255.255.0, Network specified, Host Address Range: 192.168.0.1-192.168.0.254, 254 Usable Addresses, Broadcast: 192.168.0.255"),
"8.8.8.8 255.255.224.0" => test_zci("Network: 8.8.0.0/19, Netmask: 255.255.224.0, Host #2056 specified, Host Address Range: 8.8.0.1-8.8.31.254, 8190 Usable Addresses, Broadcast: 8.8.31.255"),
"4.4.4.255/24" => test_zci("Network: 4.4.4.0/24, Netmask: 255.255.255.0, Broadcast specified, Host Address Range: 4.4.4.1-4.4.4.254, 254 Usable Addresses, Broadcast: 4.4.4.255"),
"42.24.42.24/17" => test_zci("Network: 42.24.0.0/17, Netmask: 255.255.128.0, Host #10776 specified, Host Address Range: 42.24.0.1-42.24.127.254, 32766 Usable Addresses, Broadcast: 42.24.127.255"),
"172.32.1.3/31" => test_zci("Network: 172.32.1.2/31, Netmask: 255.255.255.254, Point-To-Point (172.32.1.2, 172.32.1.3) specified"),
"10.255.255.16/32" => test_zci("Network: 10.255.255.16/32, Netmask: 255.255.255.255, Host Only specified"),
"10.1.2.3/255.0.0.0" => test_zci("Network: 10.0.0.0/8, Netmask: 255.0.0.0, Host #66051 specified, Host Address Range: 10.0.0.1-10.255.255.254, 16777214 Usable Addresses, Broadcast: 10.255.255.255"),
"192.168.16.1 23" => test_zci("Network: 192.168.16.0/23, Netmask: 255.255.254.0, Host #1 specified, Host Address Range: 192.168.16.1-192.168.17.254, 510 Usable Addresses, Broadcast: 192.168.17.255")
);
done_testing;