在perl中查找子网中的所有IP

Find all IPs from subnet in perl

我有一个带子网掩码的 IP,我想创建一个 table,其中每一行都是一个 IP。

有点像这样:

IP          | MAC  | Alive 
192.168.1.1 | ...  | yes
192.168.1.2 | ...  | no
192.168.1.3 | ...  | yes
...

对于子网为 /24 的范围,这很容易,因为我可以生成一个从 0 到 254 的 for 循环,但是我在使用 /21 子网生成 table 时遇到了问题。有没有办法在 perl 中找到最小主机、最大主机以及介于两者之间的所有内容?

我已经检查了 Net::IPNetAddr::IP 模块,但似乎无法解决我的问题。但是,我是一个 perl 新手,所以可能是我忽略了它。

编辑: 找到了如何查找第一个和最后一个地址:

my $range = "IP/subnet" ;
my $ip = new Net::IP ($range) || die;
print $ip->ip (), "\n";
print $ip->last_ip (), "\n";

现在我需要找到两者之间的 IP

你可以用 NetAddr::IP and the nth method 做到这一点。我创建了一个 helper sub,它使用单例来创建迭代器。您从子网传入任何 IP,它会为您提供一个代码参考,您可以使用它来接收下一个 IP 地址对象。它将这样做直到范围用尽,此时它 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;
}

因为 $mask$imake_ip_iterator sub 中是词法的,您可以多次调用它并为您同时使用的不同子网返回不同的迭代器。

你当然可以只用一个 while 循环和一个计数器变量来实现它,因为 nth() 将 return undef 当它被调用时使用索引之外的索引子网,但此解决方案更便携。

Net::IP 的文档在 looping 部分有一个如何执行此操作的示例。

演示:

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

如果您只有所需范围内的 IP,而没有前缀,则可以根据地址和网络掩码计算前缀。尝试这样的事情(尽管 Net::IP 可能有一种更聪明的方法来实现这一点,但我无法理解):

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