Reputation: 416
I have an IP with subnetmask and want to create a table in which every row is an IP.
Kind of like this:
IP | MAC | Alive
192.168.1.1 | ... | yes
192.168.1.2 | ... | no
192.168.1.3 | ... | yes
...
For a range with subnet /24, this is easy because I can generate a for loop from 0 to 254 but I'm having trouble with generating the table with a /21 subnet. Is there a way to find in perl what the minimum host, the maximum host and everything in between is?
I have checked the Net::IP
and the NetAddr::IP
module but don't seem a solution for my problem. However, I'm a perl newbie so it could be that I overlooked it.
edit: found how to find first and last address:
my $range = "IP/subnet" ;
my $ip = new Net::IP ($range) || die;
print $ip->ip (), "\n";
print $ip->last_ip (), "\n";
Now I need to find the IPs in between
Upvotes: 0
Views: 3682
Reputation: 206727
The docs for Net::IP
has an example for how to do this in the looping section.
Demo:
use Net::IP;
my $ip = new Net::IP("192.168.42.16/28");
do {
print $ip->ip(), "\n";
} while (++$ip);
192.168.42.16
192.168.42.17
192.168.42.18
192.168.42.19
192.168.42.20
192.168.42.21
192.168.42.22
192.168.42.23
192.168.42.24
192.168.42.25
192.168.42.26
192.168.42.27
192.168.42.28
192.168.42.29
192.168.42.30
192.168.42.31
If you only have an IP in the desired range, not the prefix, you can compute the prefix from the address and netmask. Try something like this (there probably is a more clever way of achieving this with Net::IP
though, but that's eluding me):
use Net::IP;
my $addr = "192.168.42.23";
my $len = 28;
my $mid = new Net::IP($addr, 4);
my $mask = Net::IP::ip_get_mask($len, 4);
my $first = $mid->binip() & $mask;
my $ip = new Net::IP(Net::IP::ip_bintoip($first, 4)."/$len", 4);
do {
print $ip->ip(), "\n";
} while (++$ip);
Upvotes: 4
Reputation: 54333
You can do that with NetAddr::IP and the nth
method. I created a helper sub that makes use of a singleton to create an iterator. You pass in any IP from the subnet and it gives you a code reference that you can to receive the next IP address object. It will do that until the range is exhausted, at which point it returns undef
.
use strict;
use warnings 'all';
use NetAddr::IP;
use feature 'say';
sub make_ip_iterator {
my $ip = shift;
my $mask = NetAddr::IP->new($ip);
my $i = 0;
return sub {
return $mask->nth($i++);
}
}
my $iterator = make_ip_iterator('192.168.1.1/21');
while (my $ip = $iterator->()) {
say $ip;
}
Because $mask
and $i
are lexical within the make_ip_iterator
sub, you can call it multiple times and get distinct iterators back for different subnets that you use at the same time.
You could of course implement it with only a while
loop and a counter variable because nth()
will return undef
when it's called with an index outside of the subnet, but this solution is more portable.
Upvotes: 4