Reputation: 416
I'm trying to create an IP table list where I can see which IPs are in use and which aren't.
I use the Net::IP
library for this. Code snippet:
my @IPsinrange = &getAllIPs($range) ; #range is x.x.x.x/subnet format
sub getAllIPs {
my $ip = new Net::IP ($range) || die;
my @IPs ;
# Loop
do {
push @IPs, $ip->ip() ;
} while (++$ip);
return @IPs ;
}
This works for a x.x.x.0/24 network and this works for 1.2.3.4/32 but when I use 1.2.3.4/29 for instance, the loop just dies. I thought it could be because of the fact that there were no IP adresses in use, but there are 4 IPs in that range that are alive.
Upvotes: 0
Views: 367
Reputation: 126772
I suggest that you use the Net::CIDR
function library instead. The function Net::CIDR::cidr2octets
does exactly what you need, and doesn't insist that the base address for a range is the network address
Here's an example that uses your test data 1.2.3.4/29
for the range
use strict;
use warnings 'all';
use feature 'say';
use Net::CIDR;
my @range = Net::CIDR::cidr2octets('1.2.3.4/29');
say for @range;
1.2.3.0
1.2.3.1
1.2.3.2
1.2.3.3
1.2.3.4
1.2.3.5
1.2.3.6
1.2.3.7
If you want to "normalize" a CIDR block that may not use the network address as the prefix, you can use Net::CIDR::cidr2range
followed by Net::CIDR::range2cidr
. Given '1.2.3.4/29'
, the first returns 1.2.3.0-1.2.3.7
, and when that result is passed into Net::CIDR::range2cidr
we get a normalised result
Like so
Net::CIDR::range2cidr(Net::CIDR::cidr2range('1.2.3.4/29'));
1.2.3.0/29
Upvotes: 1
Reputation: 9306
The reason this isn't working is due to the fact that the module requires you to send in a proper network address as the starting point of a given IP prefix.
Since you want to use a /29
prefix, valid ranges would be:
1.2.3.0/29
1.2.3.8/29
1.2.3.16/29
...etc
As mentioned in the comments, the documentation states that the proper usage of the constructor to get proper diagnostic output is:
$ip = Net::IP->new('1.2.3.0/29') or die (Net::IP::Error());
Upvotes: 3