Find all IPs from subnet in perl

笑着哭i 提交于 2019-12-12 02:25:19

问题


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


回答1:


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);



回答2:


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.



来源:https://stackoverflow.com/questions/38370472/find-all-ips-from-subnet-in-perl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!